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