ffcd5f13e4f66df8746b0af8843e606fb1d2cf91
[samba.git] / source4 / ntvfs / cifs / vfs_cifs.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    CIFS-on-CIFS NTVFS filesystem backend
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) James J Myers 2003 <myersjj@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 /*
23   this implements a CIFS->CIFS NTVFS filesystem backend. 
24   
25 */
26
27 #include "includes.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/raw/raw_proto.h"
30 #include "libcli/smb_composite/smb_composite.h"
31 #include "auth/auth.h"
32 #include "auth/credentials/credentials.h"
33 #include "ntvfs/ntvfs.h"
34 #include "../lib/util/dlinklist.h"
35 #include "param/param.h"
36 #include "libcli/resolve/resolve.h"
37
38 struct cvfs_file {
39         struct cvfs_file *prev, *next;
40         uint16_t fnum;
41         struct ntvfs_handle *h;
42 };
43
44 /* this is stored in ntvfs_private */
45 struct cvfs_private {
46         struct smbcli_tree *tree;
47         struct smbcli_transport *transport;
48         struct ntvfs_module_context *ntvfs;
49         struct async_info *pending;
50         struct cvfs_file *files;
51         bool map_generic;
52         bool map_trans2;
53 };
54
55
56 /* a structure used to pass information to an async handler */
57 struct async_info {
58         struct async_info *next, *prev;
59         struct cvfs_private *cvfs;
60         struct ntvfs_request *req;
61         struct smbcli_request *c_req;
62         struct cvfs_file *f;
63         void *parms;
64 };
65
66 #define CHECK_UPSTREAM_OPEN do { \
67         if (! p->transport->socket->sock) { \
68                 req->async_states->state|=NTVFS_ASYNC_STATE_CLOSE; \
69                 return NT_STATUS_CONNECTION_DISCONNECTED; \
70         } \
71 } while(0)
72
73 #define SETUP_PID do { \
74         p->tree->session->pid = req->smbpid; \
75         CHECK_UPSTREAM_OPEN; \
76 } while(0)
77
78 #define SETUP_FILE_HERE(f) do { \
79         f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
80         if (!f) return NT_STATUS_INVALID_HANDLE; \
81         io->generic.in.file.fnum = f->fnum; \
82 } while (0)
83
84 #define SETUP_FILE do { \
85         struct cvfs_file *f; \
86         SETUP_FILE_HERE(f); \
87 } while (0)
88
89 #define SETUP_PID_AND_FILE do { \
90         SETUP_PID; \
91         SETUP_FILE; \
92 } while (0)
93
94 #define CIFS_SERVER             "cifs:server"
95 #define CIFS_USER               "cifs:user"
96 #define CIFS_PASSWORD           "cifs:password"
97 #define CIFS_DOMAIN             "cifs:domain"
98 #define CIFS_SHARE              "cifs:share"
99 #define CIFS_USE_MACHINE_ACCT   "cifs:use-machine-account"
100 #define CIFS_MAP_GENERIC        "cifs:map-generic"
101 #define CIFS_MAP_TRANS2         "cifs:map-trans2"
102
103 #define CIFS_USE_MACHINE_ACCT_DEFAULT   false
104 #define CIFS_MAP_GENERIC_DEFAULT        false
105 #define CIFS_MAP_TRANS2_DEFAULT         true
106
107 /*
108   a handler for oplock break events from the server - these need to be passed
109   along to the client
110  */
111 static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
112 {
113         struct cvfs_private *p = p_private;
114         NTSTATUS status;
115         struct ntvfs_handle *h = NULL;
116         struct cvfs_file *f;
117
118         for (f=p->files; f; f=f->next) {
119                 if (f->fnum != fnum) continue;
120                 h = f->h;
121                 break;
122         }
123
124         if (!h) {
125                 DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level, fnum));
126                 return true;
127         }
128
129         DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
130         status = ntvfs_send_oplock_break(p->ntvfs, h, level);
131         if (!NT_STATUS_IS_OK(status)) return false;
132         return true;
133 }
134
135 /*
136   connect to a share - used when a tree_connect operation comes in.
137 */
138 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, 
139                              struct ntvfs_request *req,
140                              union smb_tcon *tcon)
141 {
142         NTSTATUS status;
143         struct cvfs_private *p;
144         const char *host, *user, *pass, *domain, *remote_share;
145         struct smb_composite_connect io;
146         struct composite_context *creq;
147         struct share_config *scfg = ntvfs->ctx->config;
148
149         struct cli_credentials *credentials;
150         bool machine_account;
151         const char* sharename;
152
153         switch (tcon->generic.level) {
154         case RAW_TCON_TCON:
155                 sharename = tcon->tcon.in.service;
156                 break;
157         case RAW_TCON_TCONX:
158                 sharename = tcon->tconx.in.path;
159                 break;
160         case RAW_TCON_SMB2:
161                 sharename = tcon->smb2.in.path;
162                 break;
163         default:
164                 return NT_STATUS_INVALID_LEVEL;
165         }
166
167         if (strncmp(sharename, "\\\\", 2) == 0) {
168                 char *str = strchr(sharename+2, '\\');
169                 if (str) {
170                         sharename = str + 1;
171                 }
172         }
173
174         /* Here we need to determine which server to connect to.
175          * For now we use parametric options, type cifs.
176          * Later we will use security=server and auth_server.c.
177          */
178         host = share_string_option(scfg, CIFS_SERVER, NULL);
179         user = share_string_option(scfg, CIFS_USER, NULL);
180         pass = share_string_option(scfg, CIFS_PASSWORD, NULL);
181         domain = share_string_option(scfg, CIFS_DOMAIN, NULL);
182         remote_share = share_string_option(scfg, CIFS_SHARE, NULL);
183         if (!remote_share) {
184                 remote_share = sharename;
185         }
186
187         machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT);
188
189         p = talloc_zero(ntvfs, struct cvfs_private);
190         if (!p) {
191                 return NT_STATUS_NO_MEMORY;
192         }
193
194         ntvfs->private_data = p;
195
196         if (!host) {
197                 DEBUG(1,("CIFS backend: You must supply server\n"));
198                 return NT_STATUS_INVALID_PARAMETER;
199         } 
200         
201         if (user && pass) {
202                 DEBUG(5, ("CIFS backend: Using specified password\n"));
203                 credentials = cli_credentials_init(p);
204                 if (!credentials) {
205                         return NT_STATUS_NO_MEMORY;
206                 }
207                 cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
208                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
209                 if (domain) {
210                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
211                 }
212                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
213         } else if (machine_account) {
214                 DEBUG(5, ("CIFS backend: Using machine account\n"));
215                 credentials = cli_credentials_init(p);
216                 cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
217                 if (domain) {
218                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
219                 }
220                 status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx);
221                 if (!NT_STATUS_IS_OK(status)) {
222                         return status;
223                 }
224         } else if (req->session_info->credentials) {
225                 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
226                 credentials = req->session_info->credentials;
227         } else {
228                 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
229                 return NT_STATUS_INVALID_PARAMETER;
230         }
231
232         /* connect to the server, using the smbd event context */
233         io.in.dest_host = host;
234         io.in.dest_ports = lp_smb_ports(ntvfs->ctx->lp_ctx);
235         io.in.socket_options = lp_socket_options(ntvfs->ctx->lp_ctx);
236         io.in.called_name = host;
237         io.in.credentials = credentials;
238         io.in.fallback_to_anonymous = false;
239         io.in.workgroup = lp_workgroup(ntvfs->ctx->lp_ctx);
240         io.in.service = remote_share;
241         io.in.service_type = "?????";
242         io.in.iconv_convenience = lp_iconv_convenience(ntvfs->ctx->lp_ctx);
243         io.in.gensec_settings = lp_gensec_settings(p, ntvfs->ctx->lp_ctx);
244         lp_smbcli_options(ntvfs->ctx->lp_ctx, &io.in.options);
245         lp_smbcli_session_options(ntvfs->ctx->lp_ctx, &io.in.session_options);
246
247         if (!(ntvfs->ctx->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS)) {
248                 io.in.options.use_level2_oplocks = false;
249         }
250
251         creq = smb_composite_connect_send(&io, p,
252                                           lp_resolve_context(ntvfs->ctx->lp_ctx),
253                                           ntvfs->ctx->event_ctx);
254         status = smb_composite_connect_recv(creq, p);
255         NT_STATUS_NOT_OK_RETURN(status);
256
257         p->tree = io.out.tree;
258
259         p->transport = p->tree->session->transport;
260         SETUP_PID;
261         p->ntvfs = ntvfs;
262
263         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
264         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
265         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
266         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
267
268         if (tcon->generic.level == RAW_TCON_TCONX) {
269                 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
270                 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
271         }
272
273         /* we need to receive oplock break requests from the server */
274         smbcli_oplock_handler(p->transport, oplock_handler, p);
275
276         p->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT);
277
278         p->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT);
279
280         return NT_STATUS_OK;
281 }
282
283 /*
284   disconnect from a share
285 */
286 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
287 {
288         struct cvfs_private *p = ntvfs->private_data;
289         struct async_info *a, *an;
290
291         /* first cleanup pending requests */
292         for (a=p->pending; a; a = an) {
293                 an = a->next;
294                 smbcli_request_destroy(a->c_req);
295                 talloc_free(a);
296         }
297
298         talloc_free(p);
299         ntvfs->private_data = NULL;
300
301         return NT_STATUS_OK;
302 }
303
304 /*
305   destroy an async info structure
306 */
307 static int async_info_destructor(struct async_info *async)
308 {
309         DLIST_REMOVE(async->cvfs->pending, async);
310         return 0;
311 }
312
313 /*
314   a handler for simple async replies
315   this handler can only be used for functions that don't return any
316   parameters (those that just return a status code)
317  */
318 static void async_simple(struct smbcli_request *c_req)
319 {
320         struct async_info *async = c_req->async.private_data;
321         struct ntvfs_request *req = async->req;
322         req->async_states->status = smbcli_request_simple_recv(c_req);
323         talloc_free(async);
324         req->async_states->send_fn(req);
325 }
326
327
328 /* save some typing for the simple functions */
329 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
330         if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
331         { \
332                 struct async_info *async; \
333                 async = talloc(req, struct async_info); \
334                 if (!async) return NT_STATUS_NO_MEMORY; \
335                 async->parms = io; \
336                 async->req = req; \
337                 async->f = file; \
338                 async->cvfs = p; \
339                 async->c_req = c_req; \
340                 DLIST_ADD(p->pending, async); \
341                 c_req->async.private_data = async; \
342                 talloc_set_destructor(async, async_info_destructor); \
343         } \
344         c_req->async.fn = async_fn; \
345         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
346         return NT_STATUS_OK; \
347 } while (0)
348
349 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
350
351 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
352
353 /*
354   delete a file - the dirtype specifies the file types to include in the search. 
355   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
356 */
357 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, 
358                             struct ntvfs_request *req, union smb_unlink *unl)
359 {
360         struct cvfs_private *p = ntvfs->private_data;
361         struct smbcli_request *c_req;
362
363         SETUP_PID;
364
365         /* see if the front end will allow us to perform this
366            function asynchronously.  */
367         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
368                 return smb_raw_unlink(p->tree, unl);
369         }
370
371         c_req = smb_raw_unlink_send(p->tree, unl);
372
373         SIMPLE_ASYNC_TAIL;
374 }
375
376 /*
377   a handler for async ioctl replies
378  */
379 static void async_ioctl(struct smbcli_request *c_req)
380 {
381         struct async_info *async = c_req->async.private_data;
382         struct ntvfs_request *req = async->req;
383         req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
384         talloc_free(async);
385         req->async_states->send_fn(req);
386 }
387
388 /*
389   ioctl interface
390 */
391 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, 
392                            struct ntvfs_request *req, union smb_ioctl *io)
393 {
394         struct cvfs_private *p = ntvfs->private_data;
395         struct smbcli_request *c_req;
396
397         SETUP_PID_AND_FILE;
398
399         /* see if the front end will allow us to perform this
400            function asynchronously.  */
401         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
402                 return smb_raw_ioctl(p->tree, req, io);
403         }
404
405         c_req = smb_raw_ioctl_send(p->tree, io);
406
407         ASYNC_RECV_TAIL(io, async_ioctl);
408 }
409
410 /*
411   check if a directory exists
412 */
413 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, 
414                              struct ntvfs_request *req, union smb_chkpath *cp)
415 {
416         struct cvfs_private *p = ntvfs->private_data;
417         struct smbcli_request *c_req;
418
419         SETUP_PID;
420
421         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
422                 return smb_raw_chkpath(p->tree, cp);
423         }
424
425         c_req = smb_raw_chkpath_send(p->tree, cp);
426
427         SIMPLE_ASYNC_TAIL;
428 }
429
430 /*
431   a handler for async qpathinfo replies
432  */
433 static void async_qpathinfo(struct smbcli_request *c_req)
434 {
435         struct async_info *async = c_req->async.private_data;
436         struct ntvfs_request *req = async->req;
437         req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
438         talloc_free(async);
439         req->async_states->send_fn(req);
440 }
441
442 /*
443   return info on a pathname
444 */
445 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, 
446                                struct ntvfs_request *req, union smb_fileinfo *info)
447 {
448         struct cvfs_private *p = ntvfs->private_data;
449         struct smbcli_request *c_req;
450
451         SETUP_PID;
452
453         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
454                 return smb_raw_pathinfo(p->tree, req, info);
455         }
456
457         c_req = smb_raw_pathinfo_send(p->tree, info);
458
459         ASYNC_RECV_TAIL(info, async_qpathinfo);
460 }
461
462 /*
463   a handler for async qfileinfo replies
464  */
465 static void async_qfileinfo(struct smbcli_request *c_req)
466 {
467         struct async_info *async = c_req->async.private_data;
468         struct ntvfs_request *req = async->req;
469         req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
470         talloc_free(async);
471         req->async_states->send_fn(req);
472 }
473
474 /*
475   query info on a open file
476 */
477 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, 
478                                struct ntvfs_request *req, union smb_fileinfo *io)
479 {
480         struct cvfs_private *p = ntvfs->private_data;
481         struct smbcli_request *c_req;
482
483         SETUP_PID_AND_FILE;
484
485         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
486                 return smb_raw_fileinfo(p->tree, req, io);
487         }
488
489         c_req = smb_raw_fileinfo_send(p->tree, io);
490
491         ASYNC_RECV_TAIL(io, async_qfileinfo);
492 }
493
494
495 /*
496   set info on a pathname
497 */
498 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, 
499                                  struct ntvfs_request *req, union smb_setfileinfo *st)
500 {
501         struct cvfs_private *p = ntvfs->private_data;
502         struct smbcli_request *c_req;
503
504         SETUP_PID;
505
506         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
507                 return smb_raw_setpathinfo(p->tree, st);
508         }
509
510         c_req = smb_raw_setpathinfo_send(p->tree, st);
511
512         SIMPLE_ASYNC_TAIL;
513 }
514
515
516 /*
517   a handler for async open replies
518  */
519 static void async_open(struct smbcli_request *c_req)
520 {
521         struct async_info *async = c_req->async.private_data;
522         struct cvfs_private *cvfs = async->cvfs;
523         struct ntvfs_request *req = async->req;
524         struct cvfs_file *f = async->f;
525         union smb_open *io = async->parms;
526         union smb_handle *file;
527         talloc_free(async);
528         req->async_states->status = smb_raw_open_recv(c_req, req, io);
529         SMB_OPEN_OUT_FILE(io, file);
530         f->fnum = file->fnum;
531         file->ntvfs = NULL;
532         if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
533         req->async_states->status = ntvfs_handle_set_backend_data(f->h, cvfs->ntvfs, f);
534         if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
535         file->ntvfs = f->h;
536         DLIST_ADD(cvfs->files, f);
537 failed:
538         req->async_states->send_fn(req);
539 }
540
541 /*
542   open a file
543 */
544 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, 
545                           struct ntvfs_request *req, union smb_open *io)
546 {
547         struct cvfs_private *p = ntvfs->private_data;
548         struct smbcli_request *c_req;
549         struct ntvfs_handle *h;
550         struct cvfs_file *f;
551         NTSTATUS status;
552
553         SETUP_PID;
554
555         if (io->generic.level != RAW_OPEN_GENERIC &&
556             p->map_generic) {
557                 return ntvfs_map_open(ntvfs, req, io);
558         }
559
560         status = ntvfs_handle_new(ntvfs, req, &h);
561         NT_STATUS_NOT_OK_RETURN(status);
562
563         f = talloc_zero(h, struct cvfs_file);
564         NT_STATUS_HAVE_NO_MEMORY(f);
565         f->h = h;
566
567         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
568                 union smb_handle *file;
569
570                 status = smb_raw_open(p->tree, req, io);
571                 NT_STATUS_NOT_OK_RETURN(status);
572
573                 SMB_OPEN_OUT_FILE(io, file);
574                 f->fnum = file->fnum;
575                 file->ntvfs = NULL;
576                 status = ntvfs_handle_set_backend_data(f->h, p->ntvfs, f);
577                 NT_STATUS_NOT_OK_RETURN(status);
578                 file->ntvfs = f->h;
579                 DLIST_ADD(p->files, f);
580
581                 return NT_STATUS_OK;
582         }
583
584         c_req = smb_raw_open_send(p->tree, io);
585
586         ASYNC_RECV_TAIL_F(io, async_open, f);
587 }
588
589 /*
590   create a directory
591 */
592 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, 
593                            struct ntvfs_request *req, union smb_mkdir *md)
594 {
595         struct cvfs_private *p = ntvfs->private_data;
596         struct smbcli_request *c_req;
597
598         SETUP_PID;
599
600         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
601                 return smb_raw_mkdir(p->tree, md);
602         }
603
604         c_req = smb_raw_mkdir_send(p->tree, md);
605
606         SIMPLE_ASYNC_TAIL;
607 }
608
609 /*
610   remove a directory
611 */
612 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, 
613                            struct ntvfs_request *req, struct smb_rmdir *rd)
614 {
615         struct cvfs_private *p = ntvfs->private_data;
616         struct smbcli_request *c_req;
617
618         SETUP_PID;
619
620         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
621                 return smb_raw_rmdir(p->tree, rd);
622         }
623         c_req = smb_raw_rmdir_send(p->tree, rd);
624
625         SIMPLE_ASYNC_TAIL;
626 }
627
628 /*
629   rename a set of files
630 */
631 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, 
632                             struct ntvfs_request *req, union smb_rename *ren)
633 {
634         struct cvfs_private *p = ntvfs->private_data;
635         struct smbcli_request *c_req;
636
637         SETUP_PID;
638
639         if (ren->nttrans.level == RAW_RENAME_NTTRANS) {
640                 struct cvfs_file *f;
641                 f = ntvfs_handle_get_backend_data(ren->nttrans.in.file.ntvfs, ntvfs);
642                 if (!f) return NT_STATUS_INVALID_HANDLE;
643                 ren->nttrans.in.file.fnum = f->fnum;
644         }
645
646         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
647                 return smb_raw_rename(p->tree, ren);
648         }
649
650         c_req = smb_raw_rename_send(p->tree, ren);
651
652         SIMPLE_ASYNC_TAIL;
653 }
654
655 /*
656   copy a set of files
657 */
658 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, 
659                           struct ntvfs_request *req, struct smb_copy *cp)
660 {
661         return NT_STATUS_NOT_SUPPORTED;
662 }
663
664 /*
665   a handler for async read replies
666  */
667 static void async_read(struct smbcli_request *c_req)
668 {
669         struct async_info *async = c_req->async.private_data;
670         struct ntvfs_request *req = async->req;
671         req->async_states->status = smb_raw_read_recv(c_req, async->parms);
672         talloc_free(async);
673         req->async_states->send_fn(req);
674 }
675
676 /*
677   read from a file
678 */
679 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, 
680                           struct ntvfs_request *req, union smb_read *io)
681 {
682         struct cvfs_private *p = ntvfs->private_data;
683         struct smbcli_request *c_req;
684
685         SETUP_PID;
686
687         if (io->generic.level != RAW_READ_GENERIC &&
688             p->map_generic) {
689                 return ntvfs_map_read(ntvfs, req, io);
690         }
691
692         SETUP_FILE;
693
694         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
695                 return smb_raw_read(p->tree, io);
696         }
697
698         c_req = smb_raw_read_send(p->tree, io);
699
700         ASYNC_RECV_TAIL(io, async_read);
701 }
702
703 /*
704   a handler for async write replies
705  */
706 static void async_write(struct smbcli_request *c_req)
707 {
708         struct async_info *async = c_req->async.private_data;
709         struct ntvfs_request *req = async->req;
710         req->async_states->status = smb_raw_write_recv(c_req, async->parms);
711         talloc_free(async);
712         req->async_states->send_fn(req);
713 }
714
715 /*
716   write to a file
717 */
718 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, 
719                            struct ntvfs_request *req, union smb_write *io)
720 {
721         struct cvfs_private *p = ntvfs->private_data;
722         struct smbcli_request *c_req;
723
724         SETUP_PID;
725
726         if (io->generic.level != RAW_WRITE_GENERIC &&
727             p->map_generic) {
728                 return ntvfs_map_write(ntvfs, req, io);
729         }
730         SETUP_FILE;
731
732         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
733                 return smb_raw_write(p->tree, io);
734         }
735
736         c_req = smb_raw_write_send(p->tree, io);
737
738         ASYNC_RECV_TAIL(io, async_write);
739 }
740
741 /*
742   a handler for async seek replies
743  */
744 static void async_seek(struct smbcli_request *c_req)
745 {
746         struct async_info *async = c_req->async.private_data;
747         struct ntvfs_request *req = async->req;
748         req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
749         talloc_free(async);
750         req->async_states->send_fn(req);
751 }
752
753 /*
754   seek in a file
755 */
756 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, 
757                           struct ntvfs_request *req,
758                           union smb_seek *io)
759 {
760         struct cvfs_private *p = ntvfs->private_data;
761         struct smbcli_request *c_req;
762
763         SETUP_PID_AND_FILE;
764
765         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
766                 return smb_raw_seek(p->tree, io);
767         }
768
769         c_req = smb_raw_seek_send(p->tree, io);
770
771         ASYNC_RECV_TAIL(io, async_seek);
772 }
773
774 /*
775   flush a file
776 */
777 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, 
778                            struct ntvfs_request *req,
779                            union smb_flush *io)
780 {
781         struct cvfs_private *p = ntvfs->private_data;
782         struct smbcli_request *c_req;
783
784         SETUP_PID;
785         switch (io->generic.level) {
786         case RAW_FLUSH_FLUSH:
787                 SETUP_FILE;
788                 break;
789         case RAW_FLUSH_ALL:
790                 io->generic.in.file.fnum = 0xFFFF;
791                 break;
792         case RAW_FLUSH_SMB2:
793                 return NT_STATUS_INVALID_LEVEL;
794         }
795
796         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
797                 return smb_raw_flush(p->tree, io);
798         }
799
800         c_req = smb_raw_flush_send(p->tree, io);
801
802         SIMPLE_ASYNC_TAIL;
803 }
804
805 /*
806   close a file
807 */
808 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, 
809                            struct ntvfs_request *req, union smb_close *io)
810 {
811         struct cvfs_private *p = ntvfs->private_data;
812         struct smbcli_request *c_req;
813         struct cvfs_file *f;
814         union smb_close io2;
815
816         SETUP_PID;
817
818         if (io->generic.level != RAW_CLOSE_GENERIC &&
819             p->map_generic) {
820                 return ntvfs_map_close(ntvfs, req, io);
821         }
822
823         if (io->generic.level == RAW_CLOSE_GENERIC) {
824                 ZERO_STRUCT(io2);
825                 io2.close.level = RAW_CLOSE_CLOSE;
826                 io2.close.in.file = io->generic.in.file;
827                 io2.close.in.write_time = io->generic.in.write_time;
828                 io = &io2;
829         }
830
831         SETUP_FILE_HERE(f);
832         /* Note, we aren't free-ing f, or it's h here. Should we?
833            even if file-close fails, we'll remove it from the list,
834            what else would we do? Maybe we should not remove until
835            after the proxied call completes? */
836         DLIST_REMOVE(p->files, f);
837
838         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
839                 return smb_raw_close(p->tree, io);
840         }
841
842         c_req = smb_raw_close_send(p->tree, io);
843
844         SIMPLE_ASYNC_TAIL;
845 }
846
847 /*
848   exit - closing files open by the pid
849 */
850 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, 
851                           struct ntvfs_request *req)
852 {
853         struct cvfs_private *p = ntvfs->private_data;
854         struct smbcli_request *c_req;
855
856         SETUP_PID;
857
858         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
859                 return smb_raw_exit(p->tree->session);
860         }
861
862         c_req = smb_raw_exit_send(p->tree->session);
863
864         SIMPLE_ASYNC_TAIL;
865 }
866
867 /*
868   logoff - closing files open by the user
869 */
870 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, 
871                             struct ntvfs_request *req)
872 {
873         /* we can't do this right in the cifs backend .... */
874         return NT_STATUS_OK;
875 }
876
877 /*
878   setup for an async call - nothing to do yet
879 */
880 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, 
881                                  struct ntvfs_request *req, 
882                                  void *private_data)
883 {
884         return NT_STATUS_OK;
885 }
886
887 /*
888   cancel an async call
889 */
890 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, 
891                             struct ntvfs_request *req)
892 {
893         struct cvfs_private *p = ntvfs->private_data;
894         struct async_info *a;
895
896         /* find the matching request */
897         for (a=p->pending;a;a=a->next) {
898                 if (a->req == req) {
899                         break;
900                 }
901         }
902
903         if (a == NULL) {
904                 return NT_STATUS_INVALID_PARAMETER;
905         }
906
907         return smb_raw_ntcancel(a->c_req);
908 }
909
910 /*
911   lock a byte range
912 */
913 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, 
914                           struct ntvfs_request *req, union smb_lock *io)
915 {
916         struct cvfs_private *p = ntvfs->private_data;
917         struct smbcli_request *c_req;
918
919         SETUP_PID;
920
921         if (io->generic.level != RAW_LOCK_GENERIC &&
922             p->map_generic) {
923                 return ntvfs_map_lock(ntvfs, req, io);
924         }
925         SETUP_FILE;
926
927         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
928                 return smb_raw_lock(p->tree, io);
929         }
930
931         c_req = smb_raw_lock_send(p->tree, io);
932         SIMPLE_ASYNC_TAIL;
933 }
934
935 /*
936   set info on a open file
937 */
938 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, 
939                                  struct ntvfs_request *req, 
940                                  union smb_setfileinfo *io)
941 {
942         struct cvfs_private *p = ntvfs->private_data;
943         struct smbcli_request *c_req;
944
945         SETUP_PID_AND_FILE;
946
947         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
948                 return smb_raw_setfileinfo(p->tree, io);
949         }
950         c_req = smb_raw_setfileinfo_send(p->tree, io);
951
952         SIMPLE_ASYNC_TAIL;
953 }
954
955
956 /*
957   a handler for async fsinfo replies
958  */
959 static void async_fsinfo(struct smbcli_request *c_req)
960 {
961         struct async_info *async = c_req->async.private_data;
962         struct ntvfs_request *req = async->req;
963         req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
964         talloc_free(async);
965         req->async_states->send_fn(req);
966 }
967
968 /*
969   return filesystem space info
970 */
971 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, 
972                             struct ntvfs_request *req, union smb_fsinfo *fs)
973 {
974         struct cvfs_private *p = ntvfs->private_data;
975         struct smbcli_request *c_req;
976
977         SETUP_PID;
978
979         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
980                 return smb_raw_fsinfo(p->tree, req, fs);
981         }
982
983         c_req = smb_raw_fsinfo_send(p->tree, req, fs);
984
985         ASYNC_RECV_TAIL(fs, async_fsinfo);
986 }
987
988 /*
989   return print queue info
990 */
991 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, 
992                          struct ntvfs_request *req, union smb_lpq *lpq)
993 {
994         return NT_STATUS_NOT_SUPPORTED;
995 }
996
997 /* 
998    list files in a directory matching a wildcard pattern
999 */
1000 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, 
1001                                   struct ntvfs_request *req, union smb_search_first *io, 
1002                                   void *search_private, 
1003                                   bool (*callback)(void *, const union smb_search_data *))
1004 {
1005         struct cvfs_private *p = ntvfs->private_data;
1006
1007         SETUP_PID;
1008
1009         return smb_raw_search_first(p->tree, req, io, search_private, callback);
1010 }
1011
1012 /* continue a search */
1013 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, 
1014                                  struct ntvfs_request *req, union smb_search_next *io, 
1015                                  void *search_private, 
1016                                  bool (*callback)(void *, const union smb_search_data *))
1017 {
1018         struct cvfs_private *p = ntvfs->private_data;
1019
1020         SETUP_PID;
1021
1022         return smb_raw_search_next(p->tree, req, io, search_private, callback);
1023 }
1024
1025 /* close a search */
1026 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, 
1027                                   struct ntvfs_request *req, union smb_search_close *io)
1028 {
1029         struct cvfs_private *p = ntvfs->private_data;
1030
1031         SETUP_PID;
1032
1033         return smb_raw_search_close(p->tree, io);
1034 }
1035
1036 /*
1037   a handler for async trans2 replies
1038  */
1039 static void async_trans2(struct smbcli_request *c_req)
1040 {
1041         struct async_info *async = c_req->async.private_data;
1042         struct ntvfs_request *req = async->req;
1043         req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
1044         talloc_free(async);
1045         req->async_states->send_fn(req);
1046 }
1047
1048 /* raw trans2 */
1049 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs, 
1050                             struct ntvfs_request *req,
1051                             struct smb_trans2 *trans2)
1052 {
1053         struct cvfs_private *p = ntvfs->private_data;
1054         struct smbcli_request *c_req;
1055
1056         if (p->map_trans2) {
1057                 return NT_STATUS_NOT_IMPLEMENTED;
1058         }
1059
1060         SETUP_PID;
1061
1062         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1063                 return smb_raw_trans2(p->tree, req, trans2);
1064         }
1065
1066         c_req = smb_raw_trans2_send(p->tree, trans2);
1067
1068         ASYNC_RECV_TAIL(trans2, async_trans2);
1069 }
1070
1071
1072 /* SMBtrans - not used on file shares */
1073 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, 
1074                            struct ntvfs_request *req,
1075                            struct smb_trans2 *trans2)
1076 {
1077         return NT_STATUS_ACCESS_DENIED;
1078 }
1079
1080 /*
1081   a handler for async change notify replies
1082  */
1083 static void async_changenotify(struct smbcli_request *c_req)
1084 {
1085         struct async_info *async = c_req->async.private_data;
1086         struct ntvfs_request *req = async->req;
1087         req->async_states->status = smb_raw_changenotify_recv(c_req, req, async->parms);
1088         talloc_free(async);
1089         req->async_states->send_fn(req);
1090 }
1091
1092 /* change notify request - always async */
1093 static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs, 
1094                             struct ntvfs_request *req,
1095                             union smb_notify *io)
1096 {
1097         struct cvfs_private *p = ntvfs->private_data;
1098         struct smbcli_request *c_req;
1099         int saved_timeout = p->transport->options.request_timeout;
1100         struct cvfs_file *f;
1101
1102         if (io->nttrans.level != RAW_NOTIFY_NTTRANS) {
1103                 return NT_STATUS_NOT_IMPLEMENTED;
1104         }
1105
1106         SETUP_PID;
1107
1108         f = ntvfs_handle_get_backend_data(io->nttrans.in.file.ntvfs, ntvfs);
1109         if (!f) return NT_STATUS_INVALID_HANDLE;
1110         io->nttrans.in.file.fnum = f->fnum;
1111
1112         /* this request doesn't make sense unless its async */
1113         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1114                 return NT_STATUS_INVALID_PARAMETER;
1115         }
1116
1117         /* we must not timeout on notify requests - they wait
1118            forever */
1119         p->transport->options.request_timeout = 0;
1120
1121         c_req = smb_raw_changenotify_send(p->tree, io);
1122
1123         p->transport->options.request_timeout = saved_timeout;
1124
1125         ASYNC_RECV_TAIL(io, async_changenotify);
1126 }
1127
1128 /*
1129   initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1130  */
1131 NTSTATUS ntvfs_cifs_init(void)
1132 {
1133         NTSTATUS ret;
1134         struct ntvfs_ops ops;
1135         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1136
1137         ZERO_STRUCT(ops);
1138
1139         /* fill in the name and type */
1140         ops.name = "cifs";
1141         ops.type = NTVFS_DISK;
1142         
1143         /* fill in all the operations */
1144         ops.connect = cvfs_connect;
1145         ops.disconnect = cvfs_disconnect;
1146         ops.unlink = cvfs_unlink;
1147         ops.chkpath = cvfs_chkpath;
1148         ops.qpathinfo = cvfs_qpathinfo;
1149         ops.setpathinfo = cvfs_setpathinfo;
1150         ops.open = cvfs_open;
1151         ops.mkdir = cvfs_mkdir;
1152         ops.rmdir = cvfs_rmdir;
1153         ops.rename = cvfs_rename;
1154         ops.copy = cvfs_copy;
1155         ops.ioctl = cvfs_ioctl;
1156         ops.read = cvfs_read;
1157         ops.write = cvfs_write;
1158         ops.seek = cvfs_seek;
1159         ops.flush = cvfs_flush; 
1160         ops.close = cvfs_close;
1161         ops.exit = cvfs_exit;
1162         ops.lock = cvfs_lock;
1163         ops.setfileinfo = cvfs_setfileinfo;
1164         ops.qfileinfo = cvfs_qfileinfo;
1165         ops.fsinfo = cvfs_fsinfo;
1166         ops.lpq = cvfs_lpq;
1167         ops.search_first = cvfs_search_first;
1168         ops.search_next = cvfs_search_next;
1169         ops.search_close = cvfs_search_close;
1170         ops.trans = cvfs_trans;
1171         ops.logoff = cvfs_logoff;
1172         ops.async_setup = cvfs_async_setup;
1173         ops.cancel = cvfs_cancel;
1174         ops.notify = cvfs_notify;
1175         ops.trans2 = cvfs_trans2;
1176
1177         /* register ourselves with the NTVFS subsystem. We register
1178            under the name 'cifs'. */
1179         ret = ntvfs_register(&ops, &vers);
1180
1181         if (!NT_STATUS_IS_OK(ret)) {
1182                 DEBUG(0,("Failed to register CIFS backend!\n"));
1183         }
1184         
1185         return ret;
1186 }