2 Unix SMB/CIFS implementation.
4 CIFS-on-CIFS NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
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.
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.
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/>.
23 this implements a CIFS->CIFS NTVFS filesystem backend.
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 #include "../libcli/smb/smbXcli_base.h"
40 struct cvfs_file
*prev
, *next
;
42 struct ntvfs_handle
*h
;
45 /* this is stored in ntvfs_private */
47 struct smbcli_tree
*tree
;
48 struct smbcli_transport
*transport
;
49 struct ntvfs_module_context
*ntvfs
;
50 struct async_info
*pending
;
51 struct cvfs_file
*files
;
57 /* a structure used to pass information to an async handler */
59 struct async_info
*next
, *prev
;
60 struct cvfs_private
*cvfs
;
61 struct ntvfs_request
*req
;
62 struct smbcli_request
*c_req
;
67 NTSTATUS
ntvfs_cifs_init(TALLOC_CTX
*);
69 #define CHECK_UPSTREAM_OPEN do { \
70 if (!smbXcli_conn_is_connected(p->transport->conn)) { \
71 req->async_states->state|=NTVFS_ASYNC_STATE_CLOSE; \
72 return NT_STATUS_CONNECTION_DISCONNECTED; \
76 #define SETUP_PID do { \
77 p->tree->session->pid = req->smbpid; \
78 CHECK_UPSTREAM_OPEN; \
81 #define SETUP_FILE_HERE(f) do { \
82 f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
83 if (!f) return NT_STATUS_INVALID_HANDLE; \
84 io->generic.in.file.fnum = f->fnum; \
87 #define SETUP_FILE do { \
88 struct cvfs_file *f; \
92 #define SETUP_PID_AND_FILE do { \
97 #define CIFS_SERVER "cifs:server"
98 #define CIFS_USER "cifs:user"
99 #define CIFS_PASSWORD "cifs:password"
100 #define CIFS_DOMAIN "cifs:domain"
101 #define CIFS_SHARE "cifs:share"
102 #define CIFS_USE_MACHINE_ACCT "cifs:use-machine-account"
103 #define CIFS_USE_S4U2PROXY "cifs:use-s4u2proxy"
104 #define CIFS_MAP_GENERIC "cifs:map-generic"
105 #define CIFS_MAP_TRANS2 "cifs:map-trans2"
107 #define CIFS_USE_MACHINE_ACCT_DEFAULT false
108 #define CIFS_USE_S4U2PROXY_DEFAULT false
109 #define CIFS_MAP_GENERIC_DEFAULT false
110 #define CIFS_MAP_TRANS2_DEFAULT true
113 a handler for oplock break events from the server - these need to be passed
116 static bool oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *p_private
)
118 struct cvfs_private
*p
= p_private
;
120 struct ntvfs_handle
*h
= NULL
;
123 for (f
=p
->files
; f
; f
=f
->next
) {
124 if (f
->fnum
!= fnum
) continue;
130 DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level
, fnum
));
134 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level
, fnum
));
135 status
= ntvfs_send_oplock_break(p
->ntvfs
, h
, level
);
136 if (!NT_STATUS_IS_OK(status
)) return false;
141 connect to a share - used when a tree_connect operation comes in.
143 static NTSTATUS
cvfs_connect(struct ntvfs_module_context
*ntvfs
,
144 struct ntvfs_request
*req
,
145 union smb_tcon
*tcon
)
148 struct cvfs_private
*p
;
149 const char *host
, *user
, *pass
, *domain
, *remote_share
;
150 struct smb_composite_connect io
;
151 struct composite_context
*creq
;
152 struct share_config
*scfg
= ntvfs
->ctx
->config
;
154 struct cli_credentials
*credentials
;
155 bool machine_account
;
157 const char* sharename
;
160 tmp_ctx
= talloc_new(req
);
161 if (tmp_ctx
== NULL
) {
162 return NT_STATUS_NO_MEMORY
;
165 switch (tcon
->generic
.level
) {
167 sharename
= tcon
->tcon
.in
.service
;
170 sharename
= tcon
->tconx
.in
.path
;
173 sharename
= tcon
->smb2
.in
.path
;
176 status
= NT_STATUS_INVALID_LEVEL
;
180 if (strncmp(sharename
, "\\\\", 2) == 0) {
181 char *str
= strchr(sharename
+2, '\\');
187 /* Here we need to determine which server to connect to.
188 * For now we use parametric options, type cifs.
190 host
= share_string_option(tmp_ctx
, scfg
, CIFS_SERVER
, NULL
);
191 user
= share_string_option(tmp_ctx
, scfg
, CIFS_USER
, NULL
);
192 pass
= share_string_option(tmp_ctx
, scfg
, CIFS_PASSWORD
, NULL
);
193 domain
= share_string_option(tmp_ctx
, scfg
, CIFS_DOMAIN
, NULL
);
194 remote_share
= share_string_option(tmp_ctx
, scfg
, CIFS_SHARE
, NULL
);
196 remote_share
= sharename
;
199 machine_account
= share_bool_option(scfg
, CIFS_USE_MACHINE_ACCT
, CIFS_USE_MACHINE_ACCT_DEFAULT
);
200 s4u2proxy
= share_bool_option(scfg
, CIFS_USE_S4U2PROXY
, CIFS_USE_S4U2PROXY_DEFAULT
);
202 p
= talloc_zero(ntvfs
, struct cvfs_private
);
204 status
= NT_STATUS_NO_MEMORY
;
208 ntvfs
->private_data
= p
;
211 DEBUG(1,("CIFS backend: You must supply server\n"));
212 status
= NT_STATUS_INVALID_PARAMETER
;
217 DEBUG(5, ("CIFS backend: Using specified password\n"));
218 credentials
= cli_credentials_init(p
);
220 status
= NT_STATUS_NO_MEMORY
;
223 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
224 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
226 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
228 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
229 } else if (machine_account
) {
230 DEBUG(5, ("CIFS backend: Using machine account\n"));
231 credentials
= cli_credentials_init_server(p
,
233 if (credentials
== NULL
) {
234 status
= NT_STATUS_NO_MEMORY
;
237 } else if (req
->session_info
->credentials
) {
238 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
239 credentials
= req
->session_info
->credentials
;
240 } else if (s4u2proxy
) {
241 struct ccache_container
*ccc
= NULL
;
242 const char *err_str
= NULL
;
244 char *impersonate_principal
;
246 char *target_service
;
248 impersonate_principal
= talloc_asprintf(req
, "%s@%s",
249 req
->session_info
->info
->account_name
,
250 req
->session_info
->info
->domain_name
);
252 self_service
= talloc_asprintf(req
, "cifs/%s",
253 lpcfg_netbios_name(ntvfs
->ctx
->lp_ctx
));
255 target_service
= talloc_asprintf(req
, "cifs/%s", host
);
257 DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
259 credentials
= cli_credentials_init_server(p
,
261 if (credentials
== NULL
) {
262 status
= NT_STATUS_NO_MEMORY
;
265 cli_credentials_invalidate_ccache(credentials
, CRED_SPECIFIED
);
266 cli_credentials_set_impersonate_principal(credentials
,
267 impersonate_principal
,
269 cli_credentials_set_target_service(credentials
, target_service
);
270 ret
= cli_credentials_get_ccache(credentials
,
271 ntvfs
->ctx
->event_ctx
,
276 status
= NT_STATUS_CROSSREALM_DELEGATION_FAILURE
;
277 DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n",
278 ret
, err_str
, nt_errstr(status
)));
283 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
284 status
= NT_STATUS_INTERNAL_ERROR
;
288 /* connect to the server, using the smbd event context */
289 io
.in
.dest_host
= host
;
290 io
.in
.dest_ports
= lpcfg_smb_ports(ntvfs
->ctx
->lp_ctx
);
291 io
.in
.socket_options
= lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
);
292 io
.in
.called_name
= host
;
293 io
.in
.existing_conn
= NULL
;
294 io
.in
.credentials
= credentials
;
295 io
.in
.fallback_to_anonymous
= false;
296 io
.in
.workgroup
= lpcfg_workgroup(ntvfs
->ctx
->lp_ctx
);
297 io
.in
.service
= remote_share
;
298 io
.in
.service_type
= "?????";
299 io
.in
.gensec_settings
= lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
);
300 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.options
);
301 lpcfg_smbcli_session_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.session_options
);
303 if (!(ntvfs
->ctx
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
)) {
304 io
.in
.options
.use_level2_oplocks
= false;
307 creq
= smb_composite_connect_send(&io
, p
,
308 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
309 ntvfs
->ctx
->event_ctx
);
310 status
= smb_composite_connect_recv(creq
, p
);
311 if (!NT_STATUS_IS_OK(status
)) {
315 p
->tree
= io
.out
.tree
;
317 p
->transport
= p
->tree
->session
->transport
;
321 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
322 if (ntvfs
->ctx
->fs_type
== NULL
) {
323 status
= NT_STATUS_NO_MEMORY
;
326 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
327 if (ntvfs
->ctx
->dev_type
== NULL
) {
328 status
= NT_STATUS_NO_MEMORY
;
332 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
333 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
334 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
337 /* we need to receive oplock break requests from the server */
338 smbcli_oplock_handler(p
->transport
, oplock_handler
, p
);
340 p
->map_generic
= share_bool_option(scfg
, CIFS_MAP_GENERIC
, CIFS_MAP_GENERIC_DEFAULT
);
342 p
->map_trans2
= share_bool_option(scfg
, CIFS_MAP_TRANS2
, CIFS_MAP_TRANS2_DEFAULT
);
344 status
= NT_STATUS_OK
;
347 TALLOC_FREE(tmp_ctx
);
352 disconnect from a share
354 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
356 struct cvfs_private
*p
= ntvfs
->private_data
;
357 struct async_info
*a
, *an
;
359 /* first cleanup pending requests */
360 for (a
=p
->pending
; a
; a
= an
) {
362 smbcli_request_destroy(a
->c_req
);
367 ntvfs
->private_data
= NULL
;
373 destroy an async info structure
375 static int async_info_destructor(struct async_info
*async
)
377 DLIST_REMOVE(async
->cvfs
->pending
, async
);
382 a handler for simple async replies
383 this handler can only be used for functions that don't return any
384 parameters (those that just return a status code)
386 static void async_simple(struct smbcli_request
*c_req
)
388 struct async_info
*async
= c_req
->async
.private_data
;
389 struct ntvfs_request
*req
= async
->req
;
390 req
->async_states
->status
= smbcli_request_simple_recv(c_req
);
392 req
->async_states
->send_fn(req
);
396 /* save some typing for the simple functions */
397 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
398 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
400 struct async_info *async; \
401 async = talloc(req, struct async_info); \
402 if (!async) return NT_STATUS_NO_MEMORY; \
407 async->c_req = c_req; \
408 DLIST_ADD(p->pending, async); \
409 c_req->async.private_data = async; \
410 talloc_set_destructor(async, async_info_destructor); \
412 c_req->async.fn = async_fn; \
413 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
414 return NT_STATUS_OK; \
417 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
419 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
422 delete a file - the dirtype specifies the file types to include in the search.
423 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
425 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
426 struct ntvfs_request
*req
, union smb_unlink
*unl
)
428 struct cvfs_private
*p
= ntvfs
->private_data
;
429 struct smbcli_request
*c_req
;
433 /* see if the front end will allow us to perform this
434 function asynchronously. */
435 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
436 return smb_raw_unlink(p
->tree
, unl
);
439 c_req
= smb_raw_unlink_send(p
->tree
, unl
);
445 a handler for async ioctl replies
447 static void async_ioctl(struct smbcli_request
*c_req
)
449 struct async_info
*async
= c_req
->async
.private_data
;
450 struct ntvfs_request
*req
= async
->req
;
451 req
->async_states
->status
= smb_raw_ioctl_recv(c_req
, req
, async
->parms
);
453 req
->async_states
->send_fn(req
);
459 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
460 struct ntvfs_request
*req
, union smb_ioctl
*io
)
462 struct cvfs_private
*p
= ntvfs
->private_data
;
463 struct smbcli_request
*c_req
;
467 /* see if the front end will allow us to perform this
468 function asynchronously. */
469 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
470 return smb_raw_ioctl(p
->tree
, req
, io
);
473 c_req
= smb_raw_ioctl_send(p
->tree
, io
);
475 ASYNC_RECV_TAIL(io
, async_ioctl
);
479 check if a directory exists
481 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
482 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
484 struct cvfs_private
*p
= ntvfs
->private_data
;
485 struct smbcli_request
*c_req
;
489 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
490 return smb_raw_chkpath(p
->tree
, cp
);
493 c_req
= smb_raw_chkpath_send(p
->tree
, cp
);
499 a handler for async qpathinfo replies
501 static void async_qpathinfo(struct smbcli_request
*c_req
)
503 struct async_info
*async
= c_req
->async
.private_data
;
504 struct ntvfs_request
*req
= async
->req
;
505 req
->async_states
->status
= smb_raw_pathinfo_recv(c_req
, req
, async
->parms
);
507 req
->async_states
->send_fn(req
);
511 return info on a pathname
513 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
514 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
516 struct cvfs_private
*p
= ntvfs
->private_data
;
517 struct smbcli_request
*c_req
;
521 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
522 return smb_raw_pathinfo(p
->tree
, req
, info
);
525 c_req
= smb_raw_pathinfo_send(p
->tree
, info
);
527 ASYNC_RECV_TAIL(info
, async_qpathinfo
);
531 a handler for async qfileinfo replies
533 static void async_qfileinfo(struct smbcli_request
*c_req
)
535 struct async_info
*async
= c_req
->async
.private_data
;
536 struct ntvfs_request
*req
= async
->req
;
537 req
->async_states
->status
= smb_raw_fileinfo_recv(c_req
, req
, async
->parms
);
539 req
->async_states
->send_fn(req
);
543 query info on a open file
545 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
546 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
548 struct cvfs_private
*p
= ntvfs
->private_data
;
549 struct smbcli_request
*c_req
;
553 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
554 return smb_raw_fileinfo(p
->tree
, req
, io
);
557 c_req
= smb_raw_fileinfo_send(p
->tree
, io
);
559 ASYNC_RECV_TAIL(io
, async_qfileinfo
);
564 set info on a pathname
566 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
567 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
569 struct cvfs_private
*p
= ntvfs
->private_data
;
570 struct smbcli_request
*c_req
;
574 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
575 return smb_raw_setpathinfo(p
->tree
, st
);
578 c_req
= smb_raw_setpathinfo_send(p
->tree
, st
);
585 a handler for async open replies
587 static void async_open(struct smbcli_request
*c_req
)
589 struct async_info
*async
= c_req
->async
.private_data
;
590 struct cvfs_private
*cvfs
= async
->cvfs
;
591 struct ntvfs_request
*req
= async
->req
;
592 struct cvfs_file
*f
= async
->f
;
593 union smb_open
*io
= async
->parms
;
594 union smb_handle
*file
;
599 req
->async_states
->status
= smb_raw_open_recv(c_req
, req
, io
);
600 SMB_OPEN_OUT_FILE(io
, file
);
604 f
->fnum
= file
->fnum
;
606 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
607 req
->async_states
->status
= ntvfs_handle_set_backend_data(f
->h
, cvfs
->ntvfs
, f
);
608 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
610 DLIST_ADD(cvfs
->files
, f
);
612 req
->async_states
->send_fn(req
);
618 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
619 struct ntvfs_request
*req
, union smb_open
*io
)
621 struct cvfs_private
*p
= ntvfs
->private_data
;
622 struct smbcli_request
*c_req
;
623 struct ntvfs_handle
*h
;
629 if (io
->generic
.level
!= RAW_OPEN_GENERIC
&&
631 return ntvfs_map_open(ntvfs
, req
, io
);
634 status
= ntvfs_handle_new(ntvfs
, req
, &h
);
635 NT_STATUS_NOT_OK_RETURN(status
);
637 f
= talloc_zero(h
, struct cvfs_file
);
638 NT_STATUS_HAVE_NO_MEMORY(f
);
641 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
642 union smb_handle
*file
;
644 status
= smb_raw_open(p
->tree
, req
, io
);
645 NT_STATUS_NOT_OK_RETURN(status
);
647 SMB_OPEN_OUT_FILE(io
, file
);
649 return NT_STATUS_INVALID_PARAMETER
;
651 f
->fnum
= file
->fnum
;
653 status
= ntvfs_handle_set_backend_data(f
->h
, p
->ntvfs
, f
);
654 NT_STATUS_NOT_OK_RETURN(status
);
656 DLIST_ADD(p
->files
, f
);
661 c_req
= smb_raw_open_send(p
->tree
, io
);
663 ASYNC_RECV_TAIL_F(io
, async_open
, f
);
669 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
670 struct ntvfs_request
*req
, union smb_mkdir
*md
)
672 struct cvfs_private
*p
= ntvfs
->private_data
;
673 struct smbcli_request
*c_req
;
677 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
678 return smb_raw_mkdir(p
->tree
, md
);
681 c_req
= smb_raw_mkdir_send(p
->tree
, md
);
689 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
690 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
692 struct cvfs_private
*p
= ntvfs
->private_data
;
693 struct smbcli_request
*c_req
;
697 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
698 return smb_raw_rmdir(p
->tree
, rd
);
700 c_req
= smb_raw_rmdir_send(p
->tree
, rd
);
706 rename a set of files
708 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
709 struct ntvfs_request
*req
, union smb_rename
*ren
)
711 struct cvfs_private
*p
= ntvfs
->private_data
;
712 struct smbcli_request
*c_req
;
716 if (ren
->nttrans
.level
== RAW_RENAME_NTTRANS
) {
718 f
= ntvfs_handle_get_backend_data(ren
->nttrans
.in
.file
.ntvfs
, ntvfs
);
719 if (!f
) return NT_STATUS_INVALID_HANDLE
;
720 ren
->nttrans
.in
.file
.fnum
= f
->fnum
;
723 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
724 return smb_raw_rename(p
->tree
, ren
);
727 c_req
= smb_raw_rename_send(p
->tree
, ren
);
735 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
736 struct ntvfs_request
*req
, struct smb_copy
*cp
)
738 return NT_STATUS_NOT_SUPPORTED
;
742 a handler for async read replies
744 static void async_read(struct smbcli_request
*c_req
)
746 struct async_info
*async
= c_req
->async
.private_data
;
747 struct ntvfs_request
*req
= async
->req
;
748 req
->async_states
->status
= smb_raw_read_recv(c_req
, async
->parms
);
750 req
->async_states
->send_fn(req
);
756 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
757 struct ntvfs_request
*req
, union smb_read
*io
)
759 struct cvfs_private
*p
= ntvfs
->private_data
;
760 struct smbcli_request
*c_req
;
764 if (io
->generic
.level
!= RAW_READ_GENERIC
&&
766 return ntvfs_map_read(ntvfs
, req
, io
);
771 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
772 return smb_raw_read(p
->tree
, io
);
775 c_req
= smb_raw_read_send(p
->tree
, io
);
777 ASYNC_RECV_TAIL(io
, async_read
);
781 a handler for async write replies
783 static void async_write(struct smbcli_request
*c_req
)
785 struct async_info
*async
= c_req
->async
.private_data
;
786 struct ntvfs_request
*req
= async
->req
;
787 req
->async_states
->status
= smb_raw_write_recv(c_req
, async
->parms
);
789 req
->async_states
->send_fn(req
);
795 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
796 struct ntvfs_request
*req
, union smb_write
*io
)
798 struct cvfs_private
*p
= ntvfs
->private_data
;
799 struct smbcli_request
*c_req
;
803 if (io
->generic
.level
!= RAW_WRITE_GENERIC
&&
805 return ntvfs_map_write(ntvfs
, req
, io
);
809 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
810 return smb_raw_write(p
->tree
, io
);
813 c_req
= smb_raw_write_send(p
->tree
, io
);
815 ASYNC_RECV_TAIL(io
, async_write
);
819 a handler for async seek replies
821 static void async_seek(struct smbcli_request
*c_req
)
823 struct async_info
*async
= c_req
->async
.private_data
;
824 struct ntvfs_request
*req
= async
->req
;
825 req
->async_states
->status
= smb_raw_seek_recv(c_req
, async
->parms
);
827 req
->async_states
->send_fn(req
);
833 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
834 struct ntvfs_request
*req
,
837 struct cvfs_private
*p
= ntvfs
->private_data
;
838 struct smbcli_request
*c_req
;
842 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
843 return smb_raw_seek(p
->tree
, io
);
846 c_req
= smb_raw_seek_send(p
->tree
, io
);
848 ASYNC_RECV_TAIL(io
, async_seek
);
854 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
855 struct ntvfs_request
*req
,
858 struct cvfs_private
*p
= ntvfs
->private_data
;
859 struct smbcli_request
*c_req
;
862 switch (io
->generic
.level
) {
863 case RAW_FLUSH_FLUSH
:
867 io
->generic
.in
.file
.fnum
= 0xFFFF;
870 return NT_STATUS_INVALID_LEVEL
;
873 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
874 return smb_raw_flush(p
->tree
, io
);
877 c_req
= smb_raw_flush_send(p
->tree
, io
);
885 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
886 struct ntvfs_request
*req
, union smb_close
*io
)
888 struct cvfs_private
*p
= ntvfs
->private_data
;
889 struct smbcli_request
*c_req
;
895 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
&&
897 return ntvfs_map_close(ntvfs
, req
, io
);
900 if (io
->generic
.level
== RAW_CLOSE_GENERIC
) {
902 io2
.close
.level
= RAW_CLOSE_CLOSE
;
903 io2
.close
.in
.file
= io
->generic
.in
.file
;
904 io2
.close
.in
.write_time
= io
->generic
.in
.write_time
;
909 /* Note, we aren't free-ing f, or it's h here. Should we?
910 even if file-close fails, we'll remove it from the list,
911 what else would we do? Maybe we should not remove until
912 after the proxied call completes? */
913 DLIST_REMOVE(p
->files
, f
);
915 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
916 return smb_raw_close(p
->tree
, io
);
919 c_req
= smb_raw_close_send(p
->tree
, io
);
925 exit - closing files open by the pid
927 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
928 struct ntvfs_request
*req
)
930 struct cvfs_private
*p
= ntvfs
->private_data
;
931 struct smbcli_request
*c_req
;
935 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
936 return smb_raw_exit(p
->tree
->session
);
939 c_req
= smb_raw_exit_send(p
->tree
->session
);
945 logoff - closing files open by the user
947 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
948 struct ntvfs_request
*req
)
950 /* we can't do this right in the cifs backend .... */
955 setup for an async call - nothing to do yet
957 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
958 struct ntvfs_request
*req
,
967 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
968 struct ntvfs_request
*req
)
970 struct cvfs_private
*p
= ntvfs
->private_data
;
971 struct async_info
*a
;
973 /* find the matching request */
974 for (a
=p
->pending
;a
;a
=a
->next
) {
981 return NT_STATUS_INVALID_PARAMETER
;
984 return smb_raw_ntcancel(a
->c_req
);
990 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
991 struct ntvfs_request
*req
, union smb_lock
*io
)
993 struct cvfs_private
*p
= ntvfs
->private_data
;
994 struct smbcli_request
*c_req
;
998 if (io
->generic
.level
!= RAW_LOCK_GENERIC
&&
1000 return ntvfs_map_lock(ntvfs
, req
, io
);
1004 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1005 return smb_raw_lock(p
->tree
, io
);
1008 c_req
= smb_raw_lock_send(p
->tree
, io
);
1013 set info on a open file
1015 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
1016 struct ntvfs_request
*req
,
1017 union smb_setfileinfo
*io
)
1019 struct cvfs_private
*p
= ntvfs
->private_data
;
1020 struct smbcli_request
*c_req
;
1024 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1025 return smb_raw_setfileinfo(p
->tree
, io
);
1027 c_req
= smb_raw_setfileinfo_send(p
->tree
, io
);
1034 a handler for async fsinfo replies
1036 static void async_fsinfo(struct smbcli_request
*c_req
)
1038 struct async_info
*async
= c_req
->async
.private_data
;
1039 struct ntvfs_request
*req
= async
->req
;
1040 req
->async_states
->status
= smb_raw_fsinfo_recv(c_req
, req
, async
->parms
);
1042 req
->async_states
->send_fn(req
);
1046 return filesystem space info
1048 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
1049 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
1051 struct cvfs_private
*p
= ntvfs
->private_data
;
1052 struct smbcli_request
*c_req
;
1056 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1057 return smb_raw_fsinfo(p
->tree
, req
, fs
);
1060 c_req
= smb_raw_fsinfo_send(p
->tree
, req
, fs
);
1062 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
1066 return print queue info
1068 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
1069 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
1071 return NT_STATUS_NOT_SUPPORTED
;
1075 list files in a directory matching a wildcard pattern
1077 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
1078 struct ntvfs_request
*req
, union smb_search_first
*io
,
1079 void *search_private
,
1080 bool (*callback
)(void *, const union smb_search_data
*))
1082 struct cvfs_private
*p
= ntvfs
->private_data
;
1086 return smb_raw_search_first(p
->tree
, req
, io
, search_private
, callback
);
1089 /* continue a search */
1090 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
1091 struct ntvfs_request
*req
, union smb_search_next
*io
,
1092 void *search_private
,
1093 bool (*callback
)(void *, const union smb_search_data
*))
1095 struct cvfs_private
*p
= ntvfs
->private_data
;
1099 return smb_raw_search_next(p
->tree
, req
, io
, search_private
, callback
);
1102 /* close a search */
1103 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
1104 struct ntvfs_request
*req
, union smb_search_close
*io
)
1106 struct cvfs_private
*p
= ntvfs
->private_data
;
1110 return smb_raw_search_close(p
->tree
, io
);
1114 a handler for async trans2 replies
1116 static void async_trans2(struct smbcli_request
*c_req
)
1118 struct async_info
*async
= c_req
->async
.private_data
;
1119 struct ntvfs_request
*req
= async
->req
;
1120 req
->async_states
->status
= smb_raw_trans2_recv(c_req
, req
, async
->parms
);
1122 req
->async_states
->send_fn(req
);
1126 static NTSTATUS
cvfs_trans2(struct ntvfs_module_context
*ntvfs
,
1127 struct ntvfs_request
*req
,
1128 struct smb_trans2
*trans2
)
1130 struct cvfs_private
*p
= ntvfs
->private_data
;
1131 struct smbcli_request
*c_req
;
1133 if (p
->map_trans2
) {
1134 return NT_STATUS_NOT_IMPLEMENTED
;
1139 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1140 return smb_raw_trans2(p
->tree
, req
, trans2
);
1143 c_req
= smb_raw_trans2_send(p
->tree
, trans2
);
1145 ASYNC_RECV_TAIL(trans2
, async_trans2
);
1149 /* SMBtrans - not used on file shares */
1150 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
1151 struct ntvfs_request
*req
,
1152 struct smb_trans2
*trans2
)
1154 return NT_STATUS_ACCESS_DENIED
;
1158 a handler for async change notify replies
1160 static void async_changenotify(struct smbcli_request
*c_req
)
1162 struct async_info
*async
= c_req
->async
.private_data
;
1163 struct ntvfs_request
*req
= async
->req
;
1164 req
->async_states
->status
= smb_raw_changenotify_recv(c_req
, req
, async
->parms
);
1166 req
->async_states
->send_fn(req
);
1169 /* change notify request - always async */
1170 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
1171 struct ntvfs_request
*req
,
1172 union smb_notify
*io
)
1174 struct cvfs_private
*p
= ntvfs
->private_data
;
1175 struct smbcli_request
*c_req
;
1176 int saved_timeout
= p
->transport
->options
.request_timeout
;
1177 struct cvfs_file
*f
;
1179 if (io
->nttrans
.level
!= RAW_NOTIFY_NTTRANS
) {
1180 return NT_STATUS_NOT_IMPLEMENTED
;
1185 f
= ntvfs_handle_get_backend_data(io
->nttrans
.in
.file
.ntvfs
, ntvfs
);
1186 if (!f
) return NT_STATUS_INVALID_HANDLE
;
1187 io
->nttrans
.in
.file
.fnum
= f
->fnum
;
1189 /* this request doesn't make sense unless its async */
1190 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1191 return NT_STATUS_INVALID_PARAMETER
;
1194 /* we must not timeout on notify requests - they wait
1196 p
->transport
->options
.request_timeout
= 0;
1198 c_req
= smb_raw_changenotify_send(p
->tree
, io
);
1200 p
->transport
->options
.request_timeout
= saved_timeout
;
1202 ASYNC_RECV_TAIL(io
, async_changenotify
);
1206 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1208 NTSTATUS
ntvfs_cifs_init(TALLOC_CTX
*ctx
)
1211 struct ntvfs_ops ops
;
1212 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
1216 /* fill in the name and type */
1218 ops
.type
= NTVFS_DISK
;
1220 /* fill in all the operations */
1221 ops
.connect_fn
= cvfs_connect
;
1222 ops
.disconnect_fn
= cvfs_disconnect
;
1223 ops
.unlink_fn
= cvfs_unlink
;
1224 ops
.chkpath_fn
= cvfs_chkpath
;
1225 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
1226 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
1227 ops
.open_fn
= cvfs_open
;
1228 ops
.mkdir_fn
= cvfs_mkdir
;
1229 ops
.rmdir_fn
= cvfs_rmdir
;
1230 ops
.rename_fn
= cvfs_rename
;
1231 ops
.copy_fn
= cvfs_copy
;
1232 ops
.ioctl_fn
= cvfs_ioctl
;
1233 ops
.read_fn
= cvfs_read
;
1234 ops
.write_fn
= cvfs_write
;
1235 ops
.seek_fn
= cvfs_seek
;
1236 ops
.flush_fn
= cvfs_flush
;
1237 ops
.close_fn
= cvfs_close
;
1238 ops
.exit_fn
= cvfs_exit
;
1239 ops
.lock_fn
= cvfs_lock
;
1240 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
1241 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
1242 ops
.fsinfo_fn
= cvfs_fsinfo
;
1243 ops
.lpq_fn
= cvfs_lpq
;
1244 ops
.search_first_fn
= cvfs_search_first
;
1245 ops
.search_next_fn
= cvfs_search_next
;
1246 ops
.search_close_fn
= cvfs_search_close
;
1247 ops
.trans_fn
= cvfs_trans
;
1248 ops
.logoff_fn
= cvfs_logoff
;
1249 ops
.async_setup_fn
= cvfs_async_setup
;
1250 ops
.cancel_fn
= cvfs_cancel
;
1251 ops
.notify_fn
= cvfs_notify
;
1252 ops
.trans2_fn
= cvfs_trans2
;
1254 /* register ourselves with the NTVFS subsystem. We register
1255 under the name 'cifs'. */
1256 ret
= ntvfs_register(&ops
, &vers
);
1258 if (!NT_STATUS_IS_OK(ret
)) {
1259 DEBUG(0,("Failed to register CIFS backend!\n"));