s4:vfs_ipc - fix "ipc_open" for NTTRANS create requests
[ira/wip.git] / source4 / ntvfs / ipc / vfs_ipc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    default IPC$ NTVFS backend
4
5    Copyright (C) Andrew Tridgell 2003
6    Copyright (C) Stefan (metze) Metzmacher 2004-2005
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 /*
22   this implements the IPC$ backend, called by the NTVFS subsystem to
23   handle requests on IPC$ shares
24 */
25
26
27 #include "includes.h"
28 #include "../lib/util/dlinklist.h"
29 #include "ntvfs/ntvfs.h"
30 #include "libcli/rap/rap.h"
31 #include "ntvfs/ipc/proto.h"
32 #include "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 netr_SamInfo3 *info3;
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)) return NT_STATUS_INVALID_PARAMETER;
232                 name++;
233         }
234         return NT_STATUS_OK;
235 }
236
237 /*
238   open a file - used for MSRPC pipes
239 */
240 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
241                          struct ntvfs_request *req, union smb_open *oi)
242 {
243         NTSTATUS status;
244         struct pipe_state *p;
245         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
246                                     struct ipc_private);
247         struct smb_iconv_convenience *smb_ic
248                 = lp_iconv_convenience(ipriv->ntvfs->ctx->lp_ctx);
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         struct socket_address *client_sa;
255         struct tsocket_address *client_addr;
256         struct socket_address *server_sa;
257         struct tsocket_address *server_addr;
258         int ret;
259         DATA_BLOB delegated_creds = data_blob_null;
260
261         switch (oi->generic.level) {
262         case RAW_OPEN_NTCREATEX:
263         case RAW_OPEN_NTTRANS_CREATE:
264                 fname = oi->ntcreatex.in.fname;
265                 break;
266         case RAW_OPEN_OPENX:
267                 fname = oi->openx.in.fname;
268                 break;
269         case RAW_OPEN_SMB2:
270                 fname = oi->smb2.in.fname;
271                 break;
272         default:
273                 return NT_STATUS_NOT_SUPPORTED;
274         }
275
276         directory = talloc_asprintf(req, "%s/np",
277                                     lp_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
278         NT_STATUS_HAVE_NO_MEMORY(directory);
279
280         state = talloc(req, struct ipc_open_state);
281         NT_STATUS_HAVE_NO_MEMORY(state);
282
283         status = ntvfs_handle_new(ntvfs, req, &h);
284         NT_STATUS_NOT_OK_RETURN(status);
285
286         p = talloc(h, struct pipe_state);
287         NT_STATUS_HAVE_NO_MEMORY(p);
288
289         while (fname[0] == '\\') fname++;
290
291         /* check for valid characters in name */
292         fname = strlower_talloc(p, fname);
293
294         status = validate_pipename(fname);
295         NT_STATUS_NOT_OK_RETURN(status);
296
297         p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
298         NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
299
300         p->handle = h;
301         p->ipriv = ipriv;
302
303         p->write_queue = tevent_queue_create(p, "ipc_write_queue");
304         NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
305
306         p->read_queue = tevent_queue_create(p, "ipc_read_queue");
307         NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
308
309         state->ipriv = ipriv;
310         state->p = p;
311         state->req = req;
312         state->oi = oi;
313
314         status = auth_convert_server_info_saminfo3(state,
315                                                    req->session_info->server_info,
316                                                    &state->info3);
317         NT_STATUS_NOT_OK_RETURN(status);
318
319         client_sa = ntvfs_get_peer_addr(ntvfs, state);
320         if (!client_sa) {
321                 return NT_STATUS_INTERNAL_ERROR;
322         }
323
324         server_sa = ntvfs_get_my_addr(ntvfs, state);
325         if (!server_sa) {
326                 return NT_STATUS_INTERNAL_ERROR;
327         }
328
329         ret = tsocket_address_inet_from_strings(state, "ip",
330                                                 client_sa->addr,
331                                                 client_sa->port,
332                                                 &client_addr);
333         if (ret == -1) {
334                 status = map_nt_error_from_unix(errno);
335                 return status;
336         }
337
338         ret = tsocket_address_inet_from_strings(state, "ip",
339                                                 server_sa->addr,
340                                                 server_sa->port,
341                                                 &server_addr);
342         if (ret == -1) {
343                 status = map_nt_error_from_unix(errno);
344                 return status;
345         }
346
347         if (req->session_info->credentials) {
348                 struct gssapi_creds_container *gcc;
349                 OM_uint32 gret;
350                 OM_uint32 minor_status;
351                 gss_buffer_desc cred_token;
352
353                 ret = cli_credentials_get_client_gss_creds(req->session_info->credentials,
354                                                            ipriv->ntvfs->ctx->event_ctx,
355                                                            ipriv->ntvfs->ctx->lp_ctx,
356                                                            &gcc);
357                 if (ret) {
358                         goto skip;
359                 }
360
361                 gret = gss_export_cred(&minor_status,
362                                        gcc->creds,
363                                        &cred_token);
364                 if (gret != GSS_S_COMPLETE) {
365                         return NT_STATUS_INTERNAL_ERROR;
366                 }
367
368                 if (cred_token.length) {
369                         delegated_creds = data_blob_talloc(req,
370                                                            cred_token.value,
371                                                            cred_token.length);
372                         gss_release_buffer(&minor_status, &cred_token);
373                         NT_STATUS_HAVE_NO_MEMORY(delegated_creds.data);
374                 }
375         }
376
377 skip:
378
379         subreq = tstream_npa_connect_send(p,
380                                           ipriv->ntvfs->ctx->event_ctx,
381                                           smb_ic,
382                                           directory,
383                                           fname,
384                                           client_addr,
385                                           NULL,
386                                           server_addr,
387                                           NULL,
388                                           state->info3,
389                                           req->session_info->session_key,
390                                           delegated_creds);
391         NT_STATUS_HAVE_NO_MEMORY(subreq);
392         tevent_req_set_callback(subreq, ipc_open_done, state);
393
394         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
395         return NT_STATUS_OK;
396 }
397
398 static void ipc_open_done(struct tevent_req *subreq)
399 {
400         struct ipc_open_state *state = tevent_req_callback_data(subreq,
401                                        struct ipc_open_state);
402         struct ipc_private *ipriv = state->ipriv;
403         struct pipe_state *p = state->p;
404         struct ntvfs_request *req = state->req;
405         union smb_open *oi = state->oi;
406         int ret;
407         int sys_errno;
408         NTSTATUS status;
409
410         ret = tstream_npa_connect_recv(subreq, &sys_errno,
411                                        p, &p->npipe,
412                                        &p->file_type,
413                                        &p->device_state,
414                                        &p->allocation_size);
415         TALLOC_FREE(subreq);
416         if (ret == -1) {
417                 status = map_nt_error_from_unix(sys_errno);
418                 goto reply;
419         }
420
421         DLIST_ADD(ipriv->pipe_list, p);
422         talloc_set_destructor(p, ipc_fd_destructor);
423
424         status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
425         if (!NT_STATUS_IS_OK(status)) {
426                 goto reply;
427         }
428
429         switch (oi->generic.level) {
430         case RAW_OPEN_NTCREATEX:
431                 ZERO_STRUCT(oi->ntcreatex.out);
432                 oi->ntcreatex.out.file.ntvfs    = p->handle;
433                 oi->ntcreatex.out.oplock_level  = 0;
434                 oi->ntcreatex.out.create_action = NTCREATEX_ACTION_EXISTED;
435                 oi->ntcreatex.out.create_time   = 0;
436                 oi->ntcreatex.out.access_time   = 0;
437                 oi->ntcreatex.out.write_time    = 0;
438                 oi->ntcreatex.out.change_time   = 0;
439                 oi->ntcreatex.out.attrib        = FILE_ATTRIBUTE_NORMAL;
440                 oi->ntcreatex.out.alloc_size    = p->allocation_size;
441                 oi->ntcreatex.out.size          = 0;
442                 oi->ntcreatex.out.file_type     = p->file_type;
443                 oi->ntcreatex.out.ipc_state     = p->device_state;
444                 oi->ntcreatex.out.is_directory  = 0;
445                 break;
446         case RAW_OPEN_OPENX:
447                 ZERO_STRUCT(oi->openx.out);
448                 oi->openx.out.file.ntvfs        = p->handle;
449                 oi->openx.out.attrib            = FILE_ATTRIBUTE_NORMAL;
450                 oi->openx.out.write_time        = 0;
451                 oi->openx.out.size              = 0;
452                 oi->openx.out.access            = 0;
453                 oi->openx.out.ftype             = p->file_type;
454                 oi->openx.out.devstate          = p->device_state;
455                 oi->openx.out.action            = 0;
456                 oi->openx.out.unique_fid        = 0;
457                 oi->openx.out.access_mask       = 0;
458                 oi->openx.out.unknown           = 0;
459                 break;
460         case RAW_OPEN_SMB2:
461                 ZERO_STRUCT(oi->smb2.out);
462                 oi->smb2.out.file.ntvfs         = p->handle;
463                 oi->smb2.out.oplock_level       = oi->smb2.in.oplock_level;
464                 oi->smb2.out.create_action      = NTCREATEX_ACTION_EXISTED;
465                 oi->smb2.out.create_time        = 0;
466                 oi->smb2.out.access_time        = 0;
467                 oi->smb2.out.write_time         = 0;
468                 oi->smb2.out.change_time        = 0;
469                 oi->smb2.out.alloc_size         = p->allocation_size;
470                 oi->smb2.out.size               = 0;
471                 oi->smb2.out.file_attr          = FILE_ATTRIBUTE_NORMAL;
472                 oi->smb2.out.reserved2          = 0;
473                 break;
474         default:
475                 break;
476         }
477
478 reply:
479         req->async_states->status = status;
480         req->async_states->send_fn(req);
481 }
482
483 /*
484   create a directory
485 */
486 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
487                           struct ntvfs_request *req, union smb_mkdir *md)
488 {
489         return NT_STATUS_ACCESS_DENIED;
490 }
491
492 /*
493   remove a directory
494 */
495 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
496                           struct ntvfs_request *req, struct smb_rmdir *rd)
497 {
498         return NT_STATUS_ACCESS_DENIED;
499 }
500
501 /*
502   rename a set of files
503 */
504 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
505                            struct ntvfs_request *req, union smb_rename *ren)
506 {
507         return NT_STATUS_ACCESS_DENIED;
508 }
509
510 /*
511   copy a set of files
512 */
513 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
514                          struct ntvfs_request *req, struct smb_copy *cp)
515 {
516         return NT_STATUS_ACCESS_DENIED;
517 }
518
519 struct ipc_readv_next_vector_state {
520         uint8_t *buf;
521         size_t len;
522         off_t ofs;
523         size_t remaining;
524 };
525
526 static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
527                                        uint8_t *buf, size_t len)
528 {
529         ZERO_STRUCTP(s);
530
531         s->buf = buf;
532         s->len = MIN(len, UINT16_MAX);
533         //DEBUG(0,("readv_next_vector_init[%u 0x%04X]\n", s->len, s->len));
534 }
535
536 static int ipc_readv_next_vector(struct tstream_context *stream,
537                                  void *private_data,
538                                  TALLOC_CTX *mem_ctx,
539                                  struct iovec **_vector,
540                                  size_t *count)
541 {
542         struct ipc_readv_next_vector_state *state =
543                 (struct ipc_readv_next_vector_state *)private_data;
544         struct iovec *vector;
545         ssize_t pending;
546         size_t wanted;
547
548         if (state->ofs == state->len) {
549                 *_vector = NULL;
550                 *count = 0;
551 //              DEBUG(0,("readv_next_vector done ofs[%u 0x%04X]\n",
552 //                      state->ofs, state->ofs));
553                 return 0;
554         }
555
556         pending = tstream_pending_bytes(stream);
557         if (pending == -1) {
558                 return -1;
559         }
560
561         if (pending == 0 && state->ofs != 0) {
562                 /* return a short read */
563                 *_vector = NULL;
564                 *count = 0;
565 //              DEBUG(0,("readv_next_vector short read ofs[%u 0x%04X]\n",
566 //                      state->ofs, state->ofs));
567                 return 0;
568         }
569
570         if (pending == 0) {
571                 /* we want at least one byte and recheck again */
572                 wanted = 1;
573         } else {
574                 size_t missing = state->len - state->ofs;
575                 if (pending > missing) {
576                         /* there's more available */
577                         state->remaining = pending - missing;
578                         wanted = missing;
579                 } else {
580                         /* read what we can get and recheck in the next cycle */
581                         wanted = pending;
582                 }
583         }
584
585         vector = talloc_array(mem_ctx, struct iovec, 1);
586         if (!vector) {
587                 return -1;
588         }
589
590         vector[0].iov_base = state->buf + state->ofs;
591         vector[0].iov_len = wanted;
592
593         state->ofs += wanted;
594
595         *_vector = vector;
596         *count = 1;
597         return 0;
598 }
599
600 struct ipc_read_state {
601         struct ipc_private *ipriv;
602         struct pipe_state *p;
603         struct ntvfs_request *req;
604         union smb_read *rd;
605         struct ipc_readv_next_vector_state next_vector;
606 };
607
608 static void ipc_read_done(struct tevent_req *subreq);
609
610 /*
611   read from a file
612 */
613 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
614                          struct ntvfs_request *req, union smb_read *rd)
615 {
616         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
617                                     struct ipc_private);
618         struct pipe_state *p;
619         struct ipc_read_state *state;
620         struct tevent_req *subreq;
621
622         if (rd->generic.level != RAW_READ_GENERIC) {
623                 return ntvfs_map_read(ntvfs, req, rd);
624         }
625
626         p = pipe_state_find(ipriv, rd->readx.in.file.ntvfs);
627         if (!p) {
628                 return NT_STATUS_INVALID_HANDLE;
629         }
630
631         state = talloc(req, struct ipc_read_state);
632         NT_STATUS_HAVE_NO_MEMORY(state);
633
634         state->ipriv = ipriv;
635         state->p = p;
636         state->req = req;
637         state->rd = rd;
638
639         /* rd->readx.out.data is already allocated */
640         ipc_readv_next_vector_init(&state->next_vector,
641                                    rd->readx.out.data,
642                                    rd->readx.in.maxcnt);
643
644         subreq = tstream_readv_pdu_queue_send(req,
645                                               ipriv->ntvfs->ctx->event_ctx,
646                                               p->npipe,
647                                               p->read_queue,
648                                               ipc_readv_next_vector,
649                                               &state->next_vector);
650         NT_STATUS_HAVE_NO_MEMORY(subreq);
651         tevent_req_set_callback(subreq, ipc_read_done, state);
652
653         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
654         return NT_STATUS_OK;
655 }
656
657 static void ipc_read_done(struct tevent_req *subreq)
658 {
659         struct ipc_read_state *state =
660                 tevent_req_callback_data(subreq,
661                 struct ipc_read_state);
662         struct ntvfs_request *req = state->req;
663         union smb_read *rd = state->rd;
664         int ret;
665         int sys_errno;
666         NTSTATUS status;
667
668         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
669         TALLOC_FREE(subreq);
670         if (ret == -1) {
671                 status = map_nt_error_from_unix(sys_errno);
672                 goto reply;
673         }
674
675         status = NT_STATUS_OK;
676         if (state->next_vector.remaining > 0) {
677                 status = STATUS_BUFFER_OVERFLOW;
678         }
679
680         rd->readx.out.remaining = state->next_vector.remaining;
681         rd->readx.out.compaction_mode = 0;
682         rd->readx.out.nread = ret;
683
684 reply:
685         req->async_states->status = status;
686         req->async_states->send_fn(req);
687 }
688
689 struct ipc_write_state {
690         struct ipc_private *ipriv;
691         struct pipe_state *p;
692         struct ntvfs_request *req;
693         union smb_write *wr;
694         struct iovec iov;
695 };
696
697 static void ipc_write_done(struct tevent_req *subreq);
698
699 /*
700   write to a file
701 */
702 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
703                           struct ntvfs_request *req, union smb_write *wr)
704 {
705         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
706                                     struct ipc_private);
707         struct pipe_state *p;
708         struct tevent_req *subreq;
709         struct ipc_write_state *state;
710
711         if (wr->generic.level != RAW_WRITE_GENERIC) {
712                 return ntvfs_map_write(ntvfs, req, wr);
713         }
714
715         p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
716         if (!p) {
717                 return NT_STATUS_INVALID_HANDLE;
718         }
719
720         state = talloc(req, struct ipc_write_state);
721         NT_STATUS_HAVE_NO_MEMORY(state);
722
723         state->ipriv = ipriv;
724         state->p = p;
725         state->req = req;
726         state->wr = wr;
727         state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
728         state->iov.iov_len = wr->writex.in.count;
729
730         subreq = tstream_writev_queue_send(state,
731                                            ipriv->ntvfs->ctx->event_ctx,
732                                            p->npipe,
733                                            p->write_queue,
734                                            &state->iov, 1);
735         NT_STATUS_HAVE_NO_MEMORY(subreq);
736         tevent_req_set_callback(subreq, ipc_write_done, state);
737
738         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
739         return NT_STATUS_OK;
740 }
741
742 static void ipc_write_done(struct tevent_req *subreq)
743 {
744         struct ipc_write_state *state =
745                 tevent_req_callback_data(subreq,
746                 struct ipc_write_state);
747         struct ntvfs_request *req = state->req;
748         union smb_write *wr = state->wr;
749         int ret;
750         int sys_errno;
751         NTSTATUS status;
752
753         ret = tstream_writev_queue_recv(subreq, &sys_errno);
754         TALLOC_FREE(subreq);
755         if (ret == -1) {
756                 status = map_nt_error_from_unix(sys_errno);
757                 goto reply;
758         }
759
760         status = NT_STATUS_OK;
761
762         wr->writex.out.nwritten = ret;
763         wr->writex.out.remaining = 0;
764
765 reply:
766         req->async_states->status = status;
767         req->async_states->send_fn(req);
768 }
769
770 /*
771   seek in a file
772 */
773 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
774                          struct ntvfs_request *req,
775                          union smb_seek *io)
776 {
777         return NT_STATUS_ACCESS_DENIED;
778 }
779
780 /*
781   flush a file
782 */
783 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
784                           struct ntvfs_request *req,
785                           union smb_flush *io)
786 {
787         return NT_STATUS_ACCESS_DENIED;
788 }
789
790 /*
791   close a file
792 */
793 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
794                           struct ntvfs_request *req, union smb_close *io)
795 {
796         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
797                                     struct ipc_private);
798         struct pipe_state *p;
799
800         if (io->generic.level != RAW_CLOSE_CLOSE) {
801                 return ntvfs_map_close(ntvfs, req, io);
802         }
803
804         p = pipe_state_find(ipriv, io->close.in.file.ntvfs);
805         if (!p) {
806                 return NT_STATUS_INVALID_HANDLE;
807         }
808
809         talloc_free(p);
810
811         return NT_STATUS_OK;
812 }
813
814 /*
815   exit - closing files
816 */
817 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
818                          struct ntvfs_request *req)
819 {
820         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
821                                     struct ipc_private);
822         struct pipe_state *p, *next;
823         
824         for (p=ipriv->pipe_list; p; p=next) {
825                 next = p->next;
826                 if (p->handle->session_info == req->session_info &&
827                     p->handle->smbpid == req->smbpid) {
828                         talloc_free(p);
829                 }
830         }
831
832         return NT_STATUS_OK;
833 }
834
835 /*
836   logoff - closing files open by the user
837 */
838 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
839                            struct ntvfs_request *req)
840 {
841         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
842                                     struct ipc_private);
843         struct pipe_state *p, *next;
844         
845         for (p=ipriv->pipe_list; p; p=next) {
846                 next = p->next;
847                 if (p->handle->session_info == req->session_info) {
848                         talloc_free(p);
849                 }
850         }
851
852         return NT_STATUS_OK;
853 }
854
855 /*
856   setup for an async call
857 */
858 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
859                                 struct ntvfs_request *req,
860                                 void *private_data)
861 {
862         return NT_STATUS_OK;
863 }
864
865 /*
866   cancel an async call
867 */
868 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
869                            struct ntvfs_request *req)
870 {
871         return NT_STATUS_UNSUCCESSFUL;
872 }
873
874 /*
875   lock a byte range
876 */
877 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
878                          struct ntvfs_request *req, union smb_lock *lck)
879 {
880         return NT_STATUS_ACCESS_DENIED;
881 }
882
883 /*
884   set info on a open file
885 */
886 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
887                                 struct ntvfs_request *req, union smb_setfileinfo *info)
888 {
889         return NT_STATUS_ACCESS_DENIED;
890 }
891
892 /*
893   query info on a open file
894 */
895 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
896                               struct ntvfs_request *req, union smb_fileinfo *info)
897 {
898         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
899                                     struct ipc_private);
900         struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
901         if (!p) {
902                 return NT_STATUS_INVALID_HANDLE;
903         }
904         switch (info->generic.level) {
905         case RAW_FILEINFO_GENERIC: 
906         {
907                 ZERO_STRUCT(info->generic.out);
908                 info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
909                 info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
910                 info->generic.out.alloc_size = 4096;
911                 info->generic.out.nlink = 1;
912                 /* What the heck?  Match Win2k3: IPC$ pipes are delete pending */
913                 info->generic.out.delete_pending = 1;
914                 return NT_STATUS_OK;
915         }
916         case RAW_FILEINFO_ALT_NAME_INFO:
917         case RAW_FILEINFO_ALT_NAME_INFORMATION:
918         case RAW_FILEINFO_STREAM_INFO:
919         case RAW_FILEINFO_STREAM_INFORMATION:
920         case RAW_FILEINFO_COMPRESSION_INFO:
921         case RAW_FILEINFO_COMPRESSION_INFORMATION:
922         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
923         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
924                 return NT_STATUS_INVALID_PARAMETER;
925         case  RAW_FILEINFO_ALL_EAS:
926                 return NT_STATUS_ACCESS_DENIED;
927         default:
928                 return ntvfs_map_qfileinfo(ntvfs, req, info);
929         }
930         
931         return NT_STATUS_ACCESS_DENIED;
932 }
933
934
935 /*
936   return filesystem info
937 */
938 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
939                            struct ntvfs_request *req, union smb_fsinfo *fs)
940 {
941         return NT_STATUS_ACCESS_DENIED;
942 }
943
944 /*
945   return print queue info
946 */
947 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
948                         struct ntvfs_request *req, union smb_lpq *lpq)
949 {
950         return NT_STATUS_ACCESS_DENIED;
951 }
952
953 /* 
954    list files in a directory matching a wildcard pattern
955 */
956 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
957                           struct ntvfs_request *req, union smb_search_first *io,
958                           void *search_private, 
959                           bool (*callback)(void *, const union smb_search_data *))
960 {
961         return NT_STATUS_ACCESS_DENIED;
962 }
963
964 /* 
965    continue listing files in a directory 
966 */
967 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
968                          struct ntvfs_request *req, union smb_search_next *io,
969                          void *search_private, 
970                          bool (*callback)(void *, const union smb_search_data *))
971 {
972         return NT_STATUS_ACCESS_DENIED;
973 }
974
975 /* 
976    end listing files in a directory 
977 */
978 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
979                           struct ntvfs_request *req, union smb_search_close *io)
980 {
981         return NT_STATUS_ACCESS_DENIED;
982 }
983
984 struct ipc_trans_state {
985         struct ipc_private *ipriv;
986         struct pipe_state *p;
987         struct ntvfs_request *req;
988         struct smb_trans2 *trans;
989         struct iovec writev_iov;
990         struct ipc_readv_next_vector_state next_vector;
991 };
992
993 static void ipc_trans_writev_done(struct tevent_req *subreq);
994 static void ipc_trans_readv_done(struct tevent_req *subreq);
995
996 /* SMBtrans - handle a DCERPC command */
997 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
998                                struct ntvfs_request *req, struct smb_trans2 *trans)
999 {
1000         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1001                                     struct ipc_private);
1002         struct pipe_state *p;
1003         DATA_BLOB fnum_key;
1004         uint16_t fnum;
1005         struct ipc_trans_state *state;
1006         struct tevent_req *subreq;
1007
1008         /*
1009          * the fnum is in setup[1], a 16 bit value
1010          * the setup[*] values are already in host byteorder
1011          * but ntvfs_handle_search_by_wire_key() expects
1012          * network byteorder
1013          */
1014         SSVAL(&fnum, 0, trans->in.setup[1]);
1015         fnum_key = data_blob_const(&fnum, 2);
1016
1017         p = pipe_state_find_key(ipriv, req, &fnum_key);
1018         if (!p) {
1019                 return NT_STATUS_INVALID_HANDLE;
1020         }
1021
1022         /*
1023          * Trans requests are only allowed
1024          * if no other Trans or Read is active
1025          */
1026         if (tevent_queue_length(p->read_queue) > 0) {
1027                 return NT_STATUS_PIPE_BUSY;
1028         }
1029
1030         state = talloc(req, struct ipc_trans_state);
1031         NT_STATUS_HAVE_NO_MEMORY(state);
1032
1033         trans->out.setup_count = 0;
1034         trans->out.setup = NULL;
1035         trans->out.params = data_blob(NULL, 0);
1036         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
1037         NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
1038
1039         state->ipriv = ipriv;
1040         state->p = p;
1041         state->req = req;
1042         state->trans = trans;
1043         state->writev_iov.iov_base = trans->in.data.data;
1044         state->writev_iov.iov_len = trans->in.data.length;
1045
1046         ipc_readv_next_vector_init(&state->next_vector,
1047                                    trans->out.data.data,
1048                                    trans->out.data.length);
1049
1050         subreq = tstream_writev_queue_send(state,
1051                                            ipriv->ntvfs->ctx->event_ctx,
1052                                            p->npipe,
1053                                            p->write_queue,
1054                                            &state->writev_iov, 1);
1055         NT_STATUS_HAVE_NO_MEMORY(subreq);
1056         tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
1057
1058         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1059         return NT_STATUS_OK;
1060 }
1061
1062 static void ipc_trans_writev_done(struct tevent_req *subreq)
1063 {
1064         struct ipc_trans_state *state =
1065                 tevent_req_callback_data(subreq,
1066                 struct ipc_trans_state);
1067         struct ipc_private *ipriv = state->ipriv;
1068         struct pipe_state *p = state->p;
1069         struct ntvfs_request *req = state->req;
1070         int ret;
1071         int sys_errno;
1072         NTSTATUS status;
1073
1074         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1075         TALLOC_FREE(subreq);
1076         if (ret == 0) {
1077                 status = NT_STATUS_PIPE_DISCONNECTED;
1078                 goto reply;
1079         } else if (ret == -1) {
1080                 status = map_nt_error_from_unix(sys_errno);
1081                 goto reply;
1082         }
1083
1084         subreq = tstream_readv_pdu_queue_send(state,
1085                                               ipriv->ntvfs->ctx->event_ctx,
1086                                               p->npipe,
1087                                               p->read_queue,
1088                                               ipc_readv_next_vector,
1089                                               &state->next_vector);
1090         if (!subreq) {
1091                 status = NT_STATUS_NO_MEMORY;
1092                 goto reply;
1093         }
1094         tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
1095         return;
1096
1097 reply:
1098         req->async_states->status = status;
1099         req->async_states->send_fn(req);
1100 }
1101
1102 static void ipc_trans_readv_done(struct tevent_req *subreq)
1103 {
1104         struct ipc_trans_state *state =
1105                 tevent_req_callback_data(subreq,
1106                 struct ipc_trans_state);
1107         struct ntvfs_request *req = state->req;
1108         struct smb_trans2 *trans = state->trans;
1109         int ret;
1110         int sys_errno;
1111         NTSTATUS status;
1112
1113         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1114         TALLOC_FREE(subreq);
1115         if (ret == -1) {
1116                 status = map_nt_error_from_unix(sys_errno);
1117                 goto reply;
1118         }
1119
1120         status = NT_STATUS_OK;
1121         if (state->next_vector.remaining > 0) {
1122                 status = STATUS_BUFFER_OVERFLOW;
1123         }
1124
1125         trans->out.data.length = ret;
1126
1127 reply:
1128         req->async_states->status = status;
1129         req->async_states->send_fn(req);
1130 }
1131
1132 /* SMBtrans - set named pipe state */
1133 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
1134                                       struct ntvfs_request *req, struct smb_trans2 *trans)
1135 {
1136         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1137                                     struct ipc_private);
1138         struct pipe_state *p;
1139         DATA_BLOB fnum_key;
1140
1141         /* the fnum is in setup[1] */
1142         fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
1143
1144         p = pipe_state_find_key(ipriv, req, &fnum_key);
1145         if (!p) {
1146                 return NT_STATUS_INVALID_HANDLE;
1147         }
1148
1149         if (trans->in.params.length != 2) {
1150                 return NT_STATUS_INVALID_PARAMETER;
1151         }
1152
1153         /*
1154          * TODO: pass this to the tstream_npa logic
1155          */
1156         p->device_state = SVAL(trans->in.params.data, 0);
1157
1158         trans->out.setup_count = 0;
1159         trans->out.setup = NULL;
1160         trans->out.params = data_blob(NULL, 0);
1161         trans->out.data = data_blob(NULL, 0);
1162
1163         return NT_STATUS_OK;
1164 }
1165
1166
1167 /* SMBtrans - used to provide access to SMB pipes */
1168 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
1169                                 struct ntvfs_request *req, struct smb_trans2 *trans)
1170 {
1171         NTSTATUS status;
1172
1173         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
1174                 return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
1175
1176         if (trans->in.setup_count != 2) {
1177                 return NT_STATUS_INVALID_PARAMETER;
1178         }
1179
1180         switch (trans->in.setup[0]) {
1181         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
1182                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
1183                 break;
1184         case TRANSACT_DCERPCCMD:
1185                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
1186                 break;
1187         default:
1188                 status = NT_STATUS_INVALID_PARAMETER;
1189                 break;
1190         }
1191
1192         return status;
1193 }
1194
1195 struct ipc_ioctl_state {
1196         struct ipc_private *ipriv;
1197         struct pipe_state *p;
1198         struct ntvfs_request *req;
1199         union smb_ioctl *io;
1200         struct iovec writev_iov;
1201         struct ipc_readv_next_vector_state next_vector;
1202 };
1203
1204 static void ipc_ioctl_writev_done(struct tevent_req *subreq);
1205 static void ipc_ioctl_readv_done(struct tevent_req *subreq);
1206
1207 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
1208                                struct ntvfs_request *req, union smb_ioctl *io)
1209 {
1210         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1211                                     struct ipc_private);
1212         struct pipe_state *p;
1213         struct ipc_ioctl_state *state;
1214         struct tevent_req *subreq;
1215
1216         switch (io->smb2.in.function) {
1217         case FSCTL_NAMED_PIPE_READ_WRITE:
1218                 break;
1219
1220         default:
1221                 return NT_STATUS_FS_DRIVER_REQUIRED;
1222         }
1223
1224         p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
1225         if (!p) {
1226                 return NT_STATUS_INVALID_HANDLE;
1227         }
1228
1229         /*
1230          * Trans requests are only allowed
1231          * if no other Trans or Read is active
1232          */
1233         if (tevent_queue_length(p->read_queue) > 0) {
1234                 return NT_STATUS_PIPE_BUSY;
1235         }
1236
1237         state = talloc(req, struct ipc_ioctl_state);
1238         NT_STATUS_HAVE_NO_MEMORY(state);
1239
1240         io->smb2.out._pad       = 0;
1241         io->smb2.out.function   = io->smb2.in.function;
1242         io->smb2.out.unknown2   = 0;
1243         io->smb2.out.unknown3   = 0;
1244         io->smb2.out.in         = io->smb2.in.out;
1245         io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
1246         NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
1247
1248         state->ipriv = ipriv;
1249         state->p = p;
1250         state->req = req;
1251         state->io = io;
1252         state->writev_iov.iov_base = io->smb2.in.out.data;
1253         state->writev_iov.iov_len = io->smb2.in.out.length;
1254
1255         ipc_readv_next_vector_init(&state->next_vector,
1256                                    io->smb2.out.out.data,
1257                                    io->smb2.out.out.length);
1258
1259         subreq = tstream_writev_queue_send(state,
1260                                            ipriv->ntvfs->ctx->event_ctx,
1261                                            p->npipe,
1262                                            p->write_queue,
1263                                            &state->writev_iov, 1);
1264         NT_STATUS_HAVE_NO_MEMORY(subreq);
1265         tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
1266
1267         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1268         return NT_STATUS_OK;
1269 }
1270
1271 static void ipc_ioctl_writev_done(struct tevent_req *subreq)
1272 {
1273         struct ipc_ioctl_state *state =
1274                 tevent_req_callback_data(subreq,
1275                 struct ipc_ioctl_state);
1276         struct ipc_private *ipriv = state->ipriv;
1277         struct pipe_state *p = state->p;
1278         struct ntvfs_request *req = state->req;
1279         int ret;
1280         int sys_errno;
1281         NTSTATUS status;
1282
1283         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1284         TALLOC_FREE(subreq);
1285         if (ret == -1) {
1286                 status = map_nt_error_from_unix(sys_errno);
1287                 goto reply;
1288         }
1289
1290         subreq = tstream_readv_pdu_queue_send(state,
1291                                               ipriv->ntvfs->ctx->event_ctx,
1292                                               p->npipe,
1293                                               p->read_queue,
1294                                               ipc_readv_next_vector,
1295                                               &state->next_vector);
1296         if (!subreq) {
1297                 status = NT_STATUS_NO_MEMORY;
1298                 goto reply;
1299         }
1300         tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
1301         return;
1302
1303 reply:
1304         req->async_states->status = status;
1305         req->async_states->send_fn(req);
1306 }
1307
1308 static void ipc_ioctl_readv_done(struct tevent_req *subreq)
1309 {
1310         struct ipc_ioctl_state *state =
1311                 tevent_req_callback_data(subreq,
1312                 struct ipc_ioctl_state);
1313         struct ntvfs_request *req = state->req;
1314         union smb_ioctl *io = state->io;
1315         int ret;
1316         int sys_errno;
1317         NTSTATUS status;
1318
1319         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1320         TALLOC_FREE(subreq);
1321         if (ret == -1) {
1322                 status = map_nt_error_from_unix(sys_errno);
1323                 goto reply;
1324         }
1325
1326         status = NT_STATUS_OK;
1327         if (state->next_vector.remaining > 0) {
1328                 status = STATUS_BUFFER_OVERFLOW;
1329         }
1330
1331         io->smb2.out.out.length = ret;
1332
1333 reply:
1334         req->async_states->status = status;
1335         req->async_states->send_fn(req);
1336 }
1337
1338 /*
1339   ioctl interface
1340 */
1341 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
1342                           struct ntvfs_request *req, union smb_ioctl *io)
1343 {
1344         switch (io->generic.level) {
1345         case RAW_IOCTL_SMB2:
1346                 return ipc_ioctl_smb2(ntvfs, req, io);
1347
1348         case RAW_IOCTL_SMB2_NO_HANDLE:
1349                 return NT_STATUS_FS_DRIVER_REQUIRED;
1350
1351         default:
1352                 return NT_STATUS_ACCESS_DENIED;
1353         }
1354
1355         return NT_STATUS_ACCESS_DENIED;
1356 }
1357
1358
1359 /*
1360   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
1361  */
1362 NTSTATUS ntvfs_ipc_init(void)
1363 {
1364         NTSTATUS ret;
1365         struct ntvfs_ops ops;
1366         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1367
1368         ZERO_STRUCT(ops);
1369         
1370         /* fill in the name and type */
1371         ops.name = "default";
1372         ops.type = NTVFS_IPC;
1373
1374         /* fill in all the operations */
1375         ops.connect = ipc_connect;
1376         ops.disconnect = ipc_disconnect;
1377         ops.unlink = ipc_unlink;
1378         ops.chkpath = ipc_chkpath;
1379         ops.qpathinfo = ipc_qpathinfo;
1380         ops.setpathinfo = ipc_setpathinfo;
1381         ops.open = ipc_open;
1382         ops.mkdir = ipc_mkdir;
1383         ops.rmdir = ipc_rmdir;
1384         ops.rename = ipc_rename;
1385         ops.copy = ipc_copy;
1386         ops.ioctl = ipc_ioctl;
1387         ops.read = ipc_read;
1388         ops.write = ipc_write;
1389         ops.seek = ipc_seek;
1390         ops.flush = ipc_flush;  
1391         ops.close = ipc_close;
1392         ops.exit = ipc_exit;
1393         ops.lock = ipc_lock;
1394         ops.setfileinfo = ipc_setfileinfo;
1395         ops.qfileinfo = ipc_qfileinfo;
1396         ops.fsinfo = ipc_fsinfo;
1397         ops.lpq = ipc_lpq;
1398         ops.search_first = ipc_search_first;
1399         ops.search_next = ipc_search_next;
1400         ops.search_close = ipc_search_close;
1401         ops.trans = ipc_trans;
1402         ops.logoff = ipc_logoff;
1403         ops.async_setup = ipc_async_setup;
1404         ops.cancel = ipc_cancel;
1405
1406         /* register ourselves with the NTVFS subsystem. */
1407         ret = ntvfs_register(&ops, &vers);
1408
1409         if (!NT_STATUS_IS_OK(ret)) {
1410                 DEBUG(0,("Failed to register IPC backend!\n"));
1411                 return ret;
1412         }
1413
1414         return ret;
1415 }