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