r11452: Update Heimdal to current lorikeet, including removing the ccache side
[kai/samba-autobuild/.git] / source4 / ntvfs / cifs / vfs_cifs.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    CIFS-on-CIFS NTVFS filesystem backend
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) James J Myers 2003 <myersjj@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 /*
24   this implements a CIFS->CIFS NTVFS filesystem backend. 
25   
26 */
27
28 #include "includes.h"
29 #include "lib/events/events.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "libcli/composite/composite.h"
32 #include "libcli/smb_composite/smb_composite.h"
33 #include "smb_server/smb_server.h"
34 #include "smbd/service_stream.h"
35 #include "auth/auth.h"
36
37 /* this is stored in ntvfs_private */
38 struct cvfs_private {
39         struct smbcli_tree *tree;
40         struct smbcli_transport *transport;
41         struct smbsrv_tcon *tcon;
42         BOOL map_generic;
43 };
44
45
46 /* a structure used to pass information to an async handler */
47 struct async_info {
48         struct smbsrv_request *req;
49         void *parms;
50 };
51
52 #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
53
54 /*
55   a handler for oplock break events from the server - these need to be passed
56   along to the client
57  */
58 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
59 {
60         struct cvfs_private *private = p_private;
61         
62         DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
63         return req_send_oplock_break(private->tcon, fnum, level);
64 }
65
66  /*
67   a handler for read events on a connection to a backend server
68 */
69 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, 
70                                 uint16_t flags, void *private)
71 {
72         struct cvfs_private *cvfs = talloc_get_type(private, struct cvfs_private);
73         struct smbsrv_tcon *tcon = cvfs->tcon;
74         
75         if (!smbcli_transport_process(cvfs->transport)) {
76                 /* the connection to our server is dead */
77                 talloc_free(tcon);
78         }
79 }
80
81 /*
82   connect to a share - used when a tree_connect operation comes in.
83 */
84 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, 
85                              struct smbsrv_request *req, const char *sharename)
86 {
87         struct smbsrv_tcon *tcon = req->tcon;
88         NTSTATUS status;
89         struct cvfs_private *private;
90         const char *host, *user, *pass, *domain, *remote_share;
91         struct smb_composite_connect io;
92         struct composite_context *creq;
93         struct fd_event *fde;
94
95         struct cli_credentials *credentials;
96
97         /* Here we need to determine which server to connect to.
98          * For now we use parametric options, type cifs.
99          * Later we will use security=server and auth_server.c.
100          */
101         host = lp_parm_string(req->tcon->service, "cifs", "server");
102         user = lp_parm_string(req->tcon->service, "cifs", "user");
103         pass = lp_parm_string(req->tcon->service, "cifs", "password");
104         domain = lp_parm_string(req->tcon->service, "cifs", "domain");
105         remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
106         if (!remote_share) {
107                 remote_share = sharename;
108         }
109
110         private = talloc(req->tcon, struct cvfs_private);
111         if (!private) {
112                 return NT_STATUS_NO_MEMORY;
113         }
114         ZERO_STRUCTP(private);
115
116         ntvfs->private_data = private;
117
118         if (!host) {
119                 DEBUG(1,("CIFS backend: You must supply server\n"));
120                 return NT_STATUS_INVALID_PARAMETER;
121         } 
122         
123         if (user && pass && domain) {
124                 credentials = cli_credentials_init(private);
125                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
126                 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
127                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
128                 cli_credentials_set_workstation(credentials, "vfs_cifs", CRED_SPECIFIED);
129         } else if (req->session->session_info->credentials) {
130                 credentials = req->session->session_info->credentials;
131         } else {
132                 DEBUG(1,("CIFS backend: You must supply server, user, password and domain or have delegated credentials\n"));
133                 return NT_STATUS_INVALID_PARAMETER;
134         }
135
136         /* connect to the server, using the smbd event context */
137         io.in.dest_host = host;
138         io.in.port = 0;
139         io.in.called_name = host;
140         io.in.credentials = credentials;
141         io.in.fallback_to_anonymous = False;
142         io.in.workgroup = lp_workgroup();
143         io.in.service = remote_share;
144         io.in.service_type = "?????";
145         
146         creq = smb_composite_connect_send(&io, private, tcon->smb_conn->connection->event.ctx);
147         status = smb_composite_connect_recv(creq, private);
148         NT_STATUS_NOT_OK_RETURN(status);
149
150         private->tree = io.out.tree;
151
152         private->transport = private->tree->session->transport;
153         SETUP_PID;
154         private->tcon = req->tcon;
155
156         tcon->fs_type = talloc_strdup(tcon, "NTFS");
157         tcon->dev_type = talloc_strdup(tcon, "A:");
158         
159         /* we need to receive oplock break requests from the server */
160         smbcli_oplock_handler(private->transport, oplock_handler, private);
161
162         /* take over event handling for this socket */
163         talloc_free(private->transport->socket->event.fde);
164         fde = event_add_fd(private->transport->socket->event.ctx,
165                            private,
166                            socket_get_fd(private->transport->socket->sock),
167                            EVENT_FD_READ | EVENT_FD_WRITE,
168                            cifs_socket_handler,
169                            private);
170         private->transport->socket->event.fde = fde;
171
172
173         private->map_generic = lp_parm_bool(req->tcon->service, 
174                                             "cifs", "mapgeneric", False);
175
176         return NT_STATUS_OK;
177 }
178
179 /*
180   disconnect from a share
181 */
182 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs, 
183                                 struct smbsrv_tcon *tcon)
184 {
185         struct cvfs_private *private = ntvfs->private_data;
186
187         talloc_free(private);
188
189         return NT_STATUS_OK;
190 }
191
192 /*
193   a handler for simple async replies
194   this handler can only be used for functions that don't return any
195   parameters (those that just return a status code)
196  */
197 static void async_simple(struct smbcli_request *c_req)
198 {
199         struct async_info *async = c_req->async.private;
200         struct smbsrv_request *req = async->req;
201         req->async_states->status = smbcli_request_simple_recv(c_req);
202         req->async_states->send_fn(req);
203 }
204
205
206 /* save some typing for the simple functions */
207 #define ASYNC_RECV_TAIL(io, async_fn) do { \
208         if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
209         { \
210                 struct async_info *async; \
211                 async = talloc(req, struct async_info); \
212                 if (!async) return NT_STATUS_NO_MEMORY; \
213                 async->parms = io; \
214                 async->req = req; \
215                 c_req->async.private = async; \
216         } \
217         c_req->async.fn = async_fn; \
218         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
219         return NT_STATUS_OK; \
220 } while (0)
221
222 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
223
224 /*
225   delete a file - the dirtype specifies the file types to include in the search. 
226   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
227 */
228 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, 
229                             struct smbsrv_request *req, struct smb_unlink *unl)
230 {
231         struct cvfs_private *private = ntvfs->private_data;
232         struct smbcli_request *c_req;
233
234         SETUP_PID;
235
236         /* see if the front end will allow us to perform this
237            function asynchronously.  */
238         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
239                 return smb_raw_unlink(private->tree, unl);
240         }
241
242         c_req = smb_raw_unlink_send(private->tree, unl);
243
244         SIMPLE_ASYNC_TAIL;
245 }
246
247 /*
248   a handler for async ioctl replies
249  */
250 static void async_ioctl(struct smbcli_request *c_req)
251 {
252         struct async_info *async = c_req->async.private;
253         struct smbsrv_request *req = async->req;
254         req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
255         req->async_states->send_fn(req);
256 }
257
258 /*
259   ioctl interface
260 */
261 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, 
262                                 struct smbsrv_request *req, union smb_ioctl *io)
263 {
264         struct cvfs_private *private = ntvfs->private_data;
265         struct smbcli_request *c_req;
266
267         SETUP_PID;
268
269         /* see if the front end will allow us to perform this
270            function asynchronously.  */
271         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
272                 return smb_raw_ioctl(private->tree, req, io);
273         }
274
275         c_req = smb_raw_ioctl_send(private->tree, io);
276
277         ASYNC_RECV_TAIL(io, async_ioctl);
278 }
279
280 /*
281   check if a directory exists
282 */
283 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, 
284                                 struct smbsrv_request *req, struct smb_chkpath *cp)
285 {
286         struct cvfs_private *private = ntvfs->private_data;
287         struct smbcli_request *c_req;
288
289         SETUP_PID;
290
291         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
292                 return smb_raw_chkpath(private->tree, cp);
293         }
294
295         c_req = smb_raw_chkpath_send(private->tree, cp);
296
297         SIMPLE_ASYNC_TAIL;
298 }
299
300 /*
301   a handler for async qpathinfo replies
302  */
303 static void async_qpathinfo(struct smbcli_request *c_req)
304 {
305         struct async_info *async = c_req->async.private;
306         struct smbsrv_request *req = async->req;
307         req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
308         req->async_states->send_fn(req);
309 }
310
311 /*
312   return info on a pathname
313 */
314 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, 
315                                 struct smbsrv_request *req, union smb_fileinfo *info)
316 {
317         struct cvfs_private *private = ntvfs->private_data;
318         struct smbcli_request *c_req;
319
320         SETUP_PID;
321
322         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
323                 return smb_raw_pathinfo(private->tree, req, info);
324         }
325
326         c_req = smb_raw_pathinfo_send(private->tree, info);
327
328         ASYNC_RECV_TAIL(info, async_qpathinfo);
329 }
330
331 /*
332   a handler for async qfileinfo replies
333  */
334 static void async_qfileinfo(struct smbcli_request *c_req)
335 {
336         struct async_info *async = c_req->async.private;
337         struct smbsrv_request *req = async->req;
338         req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
339         req->async_states->send_fn(req);
340 }
341
342 /*
343   query info on a open file
344 */
345 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, 
346                                 struct smbsrv_request *req, union smb_fileinfo *info)
347 {
348         struct cvfs_private *private = ntvfs->private_data;
349         struct smbcli_request *c_req;
350
351         SETUP_PID;
352
353         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
354                 return smb_raw_fileinfo(private->tree, req, info);
355         }
356
357         c_req = smb_raw_fileinfo_send(private->tree, info);
358
359         ASYNC_RECV_TAIL(info, async_qfileinfo);
360 }
361
362
363 /*
364   set info on a pathname
365 */
366 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, 
367                                 struct smbsrv_request *req, union smb_setfileinfo *st)
368 {
369         struct cvfs_private *private = ntvfs->private_data;
370         struct smbcli_request *c_req;
371
372         SETUP_PID;
373
374         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
375                 return smb_raw_setpathinfo(private->tree, st);
376         }
377
378         c_req = smb_raw_setpathinfo_send(private->tree, st);
379
380         SIMPLE_ASYNC_TAIL;
381 }
382
383
384 /*
385   a handler for async open replies
386  */
387 static void async_open(struct smbcli_request *c_req)
388 {
389         struct async_info *async = c_req->async.private;
390         struct smbsrv_request *req = async->req;
391         req->async_states->status = smb_raw_open_recv(c_req, req, async->parms);
392         req->async_states->send_fn(req);
393 }
394
395 /*
396   open a file
397 */
398 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, 
399                                 struct smbsrv_request *req, union smb_open *io)
400 {
401         struct cvfs_private *private = ntvfs->private_data;
402         struct smbcli_request *c_req;
403
404         SETUP_PID;
405
406         if (io->generic.level != RAW_OPEN_GENERIC &&
407             private->map_generic) {
408                 return ntvfs_map_open(req, io, ntvfs);
409         }
410
411         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
412                 return smb_raw_open(private->tree, req, io);
413         }
414
415         c_req = smb_raw_open_send(private->tree, io);
416
417         ASYNC_RECV_TAIL(io, async_open);
418 }
419
420 /*
421   create a directory
422 */
423 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, 
424                                 struct smbsrv_request *req, union smb_mkdir *md)
425 {
426         struct cvfs_private *private = ntvfs->private_data;
427         struct smbcli_request *c_req;
428
429         SETUP_PID;
430
431         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
432                 return smb_raw_mkdir(private->tree, md);
433         }
434
435         c_req = smb_raw_mkdir_send(private->tree, md);
436
437         SIMPLE_ASYNC_TAIL;
438 }
439
440 /*
441   remove a directory
442 */
443 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, 
444                                 struct smbsrv_request *req, struct smb_rmdir *rd)
445 {
446         struct cvfs_private *private = ntvfs->private_data;
447         struct smbcli_request *c_req;
448
449         SETUP_PID;
450
451         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
452                 return smb_raw_rmdir(private->tree, rd);
453         }
454         c_req = smb_raw_rmdir_send(private->tree, rd);
455
456         SIMPLE_ASYNC_TAIL;
457 }
458
459 /*
460   rename a set of files
461 */
462 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, 
463                                 struct smbsrv_request *req, union smb_rename *ren)
464 {
465         struct cvfs_private *private = ntvfs->private_data;
466         struct smbcli_request *c_req;
467
468         SETUP_PID;
469
470         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
471                 return smb_raw_rename(private->tree, ren);
472         }
473
474         c_req = smb_raw_rename_send(private->tree, ren);
475
476         SIMPLE_ASYNC_TAIL;
477 }
478
479 /*
480   copy a set of files
481 */
482 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, 
483                                 struct smbsrv_request *req, struct smb_copy *cp)
484 {
485         return NT_STATUS_NOT_SUPPORTED;
486 }
487
488 /*
489   a handler for async read replies
490  */
491 static void async_read(struct smbcli_request *c_req)
492 {
493         struct async_info *async = c_req->async.private;
494         struct smbsrv_request *req = async->req;
495         req->async_states->status = smb_raw_read_recv(c_req, async->parms);
496         req->async_states->send_fn(req);
497 }
498
499 /*
500   read from a file
501 */
502 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, 
503                                 struct smbsrv_request *req, union smb_read *rd)
504 {
505         struct cvfs_private *private = ntvfs->private_data;
506         struct smbcli_request *c_req;
507
508         SETUP_PID;
509
510         if (rd->generic.level != RAW_READ_GENERIC &&
511             private->map_generic) {
512                 return ntvfs_map_read(req, rd, ntvfs);
513         }
514
515         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
516                 return smb_raw_read(private->tree, rd);
517         }
518
519         c_req = smb_raw_read_send(private->tree, rd);
520
521         ASYNC_RECV_TAIL(rd, async_read);
522 }
523
524 /*
525   a handler for async write replies
526  */
527 static void async_write(struct smbcli_request *c_req)
528 {
529         struct async_info *async = c_req->async.private;
530         struct smbsrv_request *req = async->req;
531         req->async_states->status = smb_raw_write_recv(c_req, async->parms);
532         req->async_states->send_fn(req);
533 }
534
535 /*
536   write to a file
537 */
538 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, 
539                                 struct smbsrv_request *req, union smb_write *wr)
540 {
541         struct cvfs_private *private = ntvfs->private_data;
542         struct smbcli_request *c_req;
543
544         SETUP_PID;
545
546         if (wr->generic.level != RAW_WRITE_GENERIC &&
547             private->map_generic) {
548                 return ntvfs_map_write(req, wr, ntvfs);
549         }
550
551         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
552                 return smb_raw_write(private->tree, wr);
553         }
554
555         c_req = smb_raw_write_send(private->tree, wr);
556
557         ASYNC_RECV_TAIL(wr, async_write);
558 }
559
560 /*
561   a handler for async seek replies
562  */
563 static void async_seek(struct smbcli_request *c_req)
564 {
565         struct async_info *async = c_req->async.private;
566         struct smbsrv_request *req = async->req;
567         req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
568         req->async_states->send_fn(req);
569 }
570
571 /*
572   seek in a file
573 */
574 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, 
575                           struct smbsrv_request *req, struct smb_seek *io)
576 {
577         struct cvfs_private *private = ntvfs->private_data;
578         struct smbcli_request *c_req;
579
580         SETUP_PID;
581
582         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
583                 return smb_raw_seek(private->tree, io);
584         }
585
586         c_req = smb_raw_seek_send(private->tree, io);
587
588         ASYNC_RECV_TAIL(io, async_seek);
589 }
590
591 /*
592   flush a file
593 */
594 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, 
595                            struct smbsrv_request *req, struct smb_flush *io)
596 {
597         struct cvfs_private *private = ntvfs->private_data;
598         struct smbcli_request *c_req;
599
600         SETUP_PID;
601
602         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
603                 return smb_raw_flush(private->tree, io);
604         }
605
606         c_req = smb_raw_flush_send(private->tree, io);
607
608         SIMPLE_ASYNC_TAIL;
609 }
610
611 /*
612   close a file
613 */
614 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, 
615                                 struct smbsrv_request *req, union smb_close *io)
616 {
617         struct cvfs_private *private = ntvfs->private_data;
618         struct smbcli_request *c_req;
619
620         SETUP_PID;
621
622         if (io->generic.level != RAW_CLOSE_GENERIC &&
623             private->map_generic) {
624                 return ntvfs_map_close(req, io, ntvfs);
625         }
626
627         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
628                 return smb_raw_close(private->tree, io);
629         }
630
631         c_req = smb_raw_close_send(private->tree, io);
632
633         SIMPLE_ASYNC_TAIL;
634 }
635
636 /*
637   exit - closing files open by the pid
638 */
639 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, 
640                                 struct smbsrv_request *req)
641 {
642         struct cvfs_private *private = ntvfs->private_data;
643         struct smbcli_request *c_req;
644
645         SETUP_PID;
646
647         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
648                 return smb_raw_exit(private->tree->session);
649         }
650
651         c_req = smb_raw_exit_send(private->tree->session);
652
653         SIMPLE_ASYNC_TAIL;
654 }
655
656 /*
657   logoff - closing files open by the user
658 */
659 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, 
660                                 struct smbsrv_request *req)
661 {
662         /* we can't do this right in the cifs backend .... */
663         return NT_STATUS_OK;
664 }
665
666 /*
667   setup for an async call - nothing to do yet
668 */
669 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, 
670                                  struct smbsrv_request *req, 
671                                  void *private)
672 {
673         return NT_STATUS_OK;
674 }
675
676 /*
677   cancel an async call
678 */
679 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, 
680                             struct smbsrv_request *req)
681 {
682         return NT_STATUS_NOT_IMPLEMENTED;
683 }
684
685 /*
686   lock a byte range
687 */
688 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, 
689                                 struct smbsrv_request *req, union smb_lock *lck)
690 {
691         struct cvfs_private *private = ntvfs->private_data;
692         struct smbcli_request *c_req;
693
694         SETUP_PID;
695
696         if (lck->generic.level != RAW_LOCK_GENERIC &&
697             private->map_generic) {
698                 return ntvfs_map_lock(req, lck, ntvfs);
699         }
700
701         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
702                 return smb_raw_lock(private->tree, lck);
703         }
704
705         c_req = smb_raw_lock_send(private->tree, lck);
706         SIMPLE_ASYNC_TAIL;
707 }
708
709 /*
710   set info on a open file
711 */
712 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, 
713                                  struct smbsrv_request *req, 
714                                  union smb_setfileinfo *info)
715 {
716         struct cvfs_private *private = ntvfs->private_data;
717         struct smbcli_request *c_req;
718
719         SETUP_PID;
720
721         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
722                 return smb_raw_setfileinfo(private->tree, info);
723         }
724         c_req = smb_raw_setfileinfo_send(private->tree, info);
725
726         SIMPLE_ASYNC_TAIL;
727 }
728
729
730 /*
731   a handler for async fsinfo replies
732  */
733 static void async_fsinfo(struct smbcli_request *c_req)
734 {
735         struct async_info *async = c_req->async.private;
736         struct smbsrv_request *req = async->req;
737         req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
738         req->async_states->send_fn(req);
739 }
740
741 /*
742   return filesystem space info
743 */
744 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, 
745                                 struct smbsrv_request *req, union smb_fsinfo *fs)
746 {
747         struct cvfs_private *private = ntvfs->private_data;
748         struct smbcli_request *c_req;
749
750         SETUP_PID;
751
752         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
753                 return smb_raw_fsinfo(private->tree, req, fs);
754         }
755
756         c_req = smb_raw_fsinfo_send(private->tree, req, fs);
757
758         ASYNC_RECV_TAIL(fs, async_fsinfo);
759 }
760
761 /*
762   return print queue info
763 */
764 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, 
765                                 struct smbsrv_request *req, union smb_lpq *lpq)
766 {
767         return NT_STATUS_NOT_SUPPORTED;
768 }
769
770 /* 
771    list files in a directory matching a wildcard pattern
772 */
773 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, 
774                                   struct smbsrv_request *req, union smb_search_first *io, 
775                                   void *search_private, 
776                                   BOOL (*callback)(void *, union smb_search_data *))
777 {
778         struct cvfs_private *private = ntvfs->private_data;
779
780         SETUP_PID;
781
782         return smb_raw_search_first(private->tree, req, io, search_private, callback);
783 }
784
785 /* continue a search */
786 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, 
787                                  struct smbsrv_request *req, union smb_search_next *io, 
788                                  void *search_private, 
789                                  BOOL (*callback)(void *, union smb_search_data *))
790 {
791         struct cvfs_private *private = ntvfs->private_data;
792
793         SETUP_PID;
794
795         return smb_raw_search_next(private->tree, req, io, search_private, callback);
796 }
797
798 /* close a search */
799 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, 
800                                   struct smbsrv_request *req, union smb_search_close *io)
801 {
802         struct cvfs_private *private = ntvfs->private_data;
803
804         SETUP_PID;
805
806         return smb_raw_search_close(private->tree, io);
807 }
808
809 /*
810   a handler for async trans2 replies
811  */
812 static void async_trans2(struct smbcli_request *c_req)
813 {
814         struct async_info *async = c_req->async.private;
815         struct smbsrv_request *req = async->req;
816         req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
817         req->async_states->send_fn(req);
818 }
819
820 /* raw trans2 */
821 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs, 
822                                 struct smbsrv_request *req, struct smb_trans2 *trans2)
823 {
824         struct cvfs_private *private = ntvfs->private_data;
825         struct smbcli_request *c_req;
826
827         SETUP_PID;
828
829         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
830                 return smb_raw_trans2(private->tree, req, trans2);
831         }
832
833         c_req = smb_raw_trans2_send(private->tree, trans2);
834
835         ASYNC_RECV_TAIL(trans2, async_trans2);
836 }
837
838
839 /* SMBtrans - not used on file shares */
840 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, 
841                                 struct smbsrv_request *req, struct smb_trans2 *trans2)
842 {
843         return NT_STATUS_ACCESS_DENIED;
844 }
845
846 /*
847   initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
848  */
849 NTSTATUS ntvfs_cifs_init(void)
850 {
851         NTSTATUS ret;
852         struct ntvfs_ops ops;
853
854         ZERO_STRUCT(ops);
855
856         /* fill in the name and type */
857         ops.name = "cifs";
858         ops.type = NTVFS_DISK;
859         
860         /* fill in all the operations */
861         ops.connect = cvfs_connect;
862         ops.disconnect = cvfs_disconnect;
863         ops.unlink = cvfs_unlink;
864         ops.chkpath = cvfs_chkpath;
865         ops.qpathinfo = cvfs_qpathinfo;
866         ops.setpathinfo = cvfs_setpathinfo;
867         ops.openfile = cvfs_open;
868         ops.mkdir = cvfs_mkdir;
869         ops.rmdir = cvfs_rmdir;
870         ops.rename = cvfs_rename;
871         ops.copy = cvfs_copy;
872         ops.ioctl = cvfs_ioctl;
873         ops.read = cvfs_read;
874         ops.write = cvfs_write;
875         ops.seek = cvfs_seek;
876         ops.flush = cvfs_flush; 
877         ops.close = cvfs_close;
878         ops.exit = cvfs_exit;
879         ops.lock = cvfs_lock;
880         ops.setfileinfo = cvfs_setfileinfo;
881         ops.qfileinfo = cvfs_qfileinfo;
882         ops.fsinfo = cvfs_fsinfo;
883         ops.lpq = cvfs_lpq;
884         ops.search_first = cvfs_search_first;
885         ops.search_next = cvfs_search_next;
886         ops.search_close = cvfs_search_close;
887         ops.trans = cvfs_trans;
888         ops.logoff = cvfs_logoff;
889         ops.async_setup = cvfs_async_setup;
890         ops.cancel = cvfs_cancel;
891
892         if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
893                 ops.trans2 = cvfs_trans2;
894         }
895
896         /* register ourselves with the NTVFS subsystem. We register
897            under the name 'cifs'. */
898         ret = ntvfs_register(&ops);
899
900         if (!NT_STATUS_IS_OK(ret)) {
901                 DEBUG(0,("Failed to register CIFS backend!\n"));
902         }
903         
904         return ret;
905 }