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