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