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(void);
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(p
);
232 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
234 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
236 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
237 if (!NT_STATUS_IS_OK(status
)) {
240 } else if (req
->session_info
->credentials
) {
241 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
242 credentials
= req
->session_info
->credentials
;
243 } else if (s4u2proxy
) {
244 struct ccache_container
*ccc
= NULL
;
245 const char *err_str
= NULL
;
247 char *impersonate_principal
;
249 char *target_service
;
251 impersonate_principal
= talloc_asprintf(req
, "%s@%s",
252 req
->session_info
->info
->account_name
,
253 req
->session_info
->info
->domain_name
);
255 self_service
= talloc_asprintf(req
, "cifs/%s",
256 lpcfg_netbios_name(ntvfs
->ctx
->lp_ctx
));
258 target_service
= talloc_asprintf(req
, "cifs/%s", host
);
260 DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
262 credentials
= cli_credentials_init(p
);
263 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
265 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
267 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
268 if (!NT_STATUS_IS_OK(status
)) {
271 cli_credentials_invalidate_ccache(credentials
, CRED_SPECIFIED
);
272 cli_credentials_set_impersonate_principal(credentials
,
273 impersonate_principal
,
275 cli_credentials_set_target_service(credentials
, target_service
);
276 ret
= cli_credentials_get_ccache(credentials
,
277 ntvfs
->ctx
->event_ctx
,
282 status
= NT_STATUS_CROSSREALM_DELEGATION_FAILURE
;
283 DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n",
284 ret
, err_str
, nt_errstr(status
)));
289 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
290 status
= NT_STATUS_INTERNAL_ERROR
;
294 /* connect to the server, using the smbd event context */
295 io
.in
.dest_host
= host
;
296 io
.in
.dest_ports
= lpcfg_smb_ports(ntvfs
->ctx
->lp_ctx
);
297 io
.in
.socket_options
= lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
);
298 io
.in
.called_name
= host
;
299 io
.in
.credentials
= credentials
;
300 io
.in
.fallback_to_anonymous
= false;
301 io
.in
.workgroup
= lpcfg_workgroup(ntvfs
->ctx
->lp_ctx
);
302 io
.in
.service
= remote_share
;
303 io
.in
.service_type
= "?????";
304 io
.in
.gensec_settings
= lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
);
305 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.options
);
306 lpcfg_smbcli_session_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.session_options
);
308 if (!(ntvfs
->ctx
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
)) {
309 io
.in
.options
.use_level2_oplocks
= false;
312 creq
= smb_composite_connect_send(&io
, p
,
313 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
314 ntvfs
->ctx
->event_ctx
);
315 status
= smb_composite_connect_recv(creq
, p
);
316 if (!NT_STATUS_IS_OK(status
)) {
320 p
->tree
= io
.out
.tree
;
322 p
->transport
= p
->tree
->session
->transport
;
326 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
327 if (ntvfs
->ctx
->fs_type
== NULL
) {
328 status
= NT_STATUS_NO_MEMORY
;
331 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
332 if (ntvfs
->ctx
->dev_type
== NULL
) {
333 status
= NT_STATUS_NO_MEMORY
;
337 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
338 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
339 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
342 /* we need to receive oplock break requests from the server */
343 smbcli_oplock_handler(p
->transport
, oplock_handler
, p
);
345 p
->map_generic
= share_bool_option(scfg
, CIFS_MAP_GENERIC
, CIFS_MAP_GENERIC_DEFAULT
);
347 p
->map_trans2
= share_bool_option(scfg
, CIFS_MAP_TRANS2
, CIFS_MAP_TRANS2_DEFAULT
);
349 status
= NT_STATUS_OK
;
352 TALLOC_FREE(tmp_ctx
);
357 disconnect from a share
359 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
361 struct cvfs_private
*p
= ntvfs
->private_data
;
362 struct async_info
*a
, *an
;
364 /* first cleanup pending requests */
365 for (a
=p
->pending
; a
; a
= an
) {
367 smbcli_request_destroy(a
->c_req
);
372 ntvfs
->private_data
= NULL
;
378 destroy an async info structure
380 static int async_info_destructor(struct async_info
*async
)
382 DLIST_REMOVE(async
->cvfs
->pending
, async
);
387 a handler for simple async replies
388 this handler can only be used for functions that don't return any
389 parameters (those that just return a status code)
391 static void async_simple(struct smbcli_request
*c_req
)
393 struct async_info
*async
= c_req
->async
.private_data
;
394 struct ntvfs_request
*req
= async
->req
;
395 req
->async_states
->status
= smbcli_request_simple_recv(c_req
);
397 req
->async_states
->send_fn(req
);
401 /* save some typing for the simple functions */
402 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
403 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
405 struct async_info *async; \
406 async = talloc(req, struct async_info); \
407 if (!async) return NT_STATUS_NO_MEMORY; \
412 async->c_req = c_req; \
413 DLIST_ADD(p->pending, async); \
414 c_req->async.private_data = async; \
415 talloc_set_destructor(async, async_info_destructor); \
417 c_req->async.fn = async_fn; \
418 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
419 return NT_STATUS_OK; \
422 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
424 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
427 delete a file - the dirtype specifies the file types to include in the search.
428 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
430 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
431 struct ntvfs_request
*req
, union smb_unlink
*unl
)
433 struct cvfs_private
*p
= ntvfs
->private_data
;
434 struct smbcli_request
*c_req
;
438 /* see if the front end will allow us to perform this
439 function asynchronously. */
440 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
441 return smb_raw_unlink(p
->tree
, unl
);
444 c_req
= smb_raw_unlink_send(p
->tree
, unl
);
450 a handler for async ioctl replies
452 static void async_ioctl(struct smbcli_request
*c_req
)
454 struct async_info
*async
= c_req
->async
.private_data
;
455 struct ntvfs_request
*req
= async
->req
;
456 req
->async_states
->status
= smb_raw_ioctl_recv(c_req
, req
, async
->parms
);
458 req
->async_states
->send_fn(req
);
464 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
465 struct ntvfs_request
*req
, union smb_ioctl
*io
)
467 struct cvfs_private
*p
= ntvfs
->private_data
;
468 struct smbcli_request
*c_req
;
472 /* see if the front end will allow us to perform this
473 function asynchronously. */
474 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
475 return smb_raw_ioctl(p
->tree
, req
, io
);
478 c_req
= smb_raw_ioctl_send(p
->tree
, io
);
480 ASYNC_RECV_TAIL(io
, async_ioctl
);
484 check if a directory exists
486 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
487 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
489 struct cvfs_private
*p
= ntvfs
->private_data
;
490 struct smbcli_request
*c_req
;
494 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
495 return smb_raw_chkpath(p
->tree
, cp
);
498 c_req
= smb_raw_chkpath_send(p
->tree
, cp
);
504 a handler for async qpathinfo replies
506 static void async_qpathinfo(struct smbcli_request
*c_req
)
508 struct async_info
*async
= c_req
->async
.private_data
;
509 struct ntvfs_request
*req
= async
->req
;
510 req
->async_states
->status
= smb_raw_pathinfo_recv(c_req
, req
, async
->parms
);
512 req
->async_states
->send_fn(req
);
516 return info on a pathname
518 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
519 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
521 struct cvfs_private
*p
= ntvfs
->private_data
;
522 struct smbcli_request
*c_req
;
526 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
527 return smb_raw_pathinfo(p
->tree
, req
, info
);
530 c_req
= smb_raw_pathinfo_send(p
->tree
, info
);
532 ASYNC_RECV_TAIL(info
, async_qpathinfo
);
536 a handler for async qfileinfo replies
538 static void async_qfileinfo(struct smbcli_request
*c_req
)
540 struct async_info
*async
= c_req
->async
.private_data
;
541 struct ntvfs_request
*req
= async
->req
;
542 req
->async_states
->status
= smb_raw_fileinfo_recv(c_req
, req
, async
->parms
);
544 req
->async_states
->send_fn(req
);
548 query info on a open file
550 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
551 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
553 struct cvfs_private
*p
= ntvfs
->private_data
;
554 struct smbcli_request
*c_req
;
558 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
559 return smb_raw_fileinfo(p
->tree
, req
, io
);
562 c_req
= smb_raw_fileinfo_send(p
->tree
, io
);
564 ASYNC_RECV_TAIL(io
, async_qfileinfo
);
569 set info on a pathname
571 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
572 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
574 struct cvfs_private
*p
= ntvfs
->private_data
;
575 struct smbcli_request
*c_req
;
579 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
580 return smb_raw_setpathinfo(p
->tree
, st
);
583 c_req
= smb_raw_setpathinfo_send(p
->tree
, st
);
590 a handler for async open replies
592 static void async_open(struct smbcli_request
*c_req
)
594 struct async_info
*async
= c_req
->async
.private_data
;
595 struct cvfs_private
*cvfs
= async
->cvfs
;
596 struct ntvfs_request
*req
= async
->req
;
597 struct cvfs_file
*f
= async
->f
;
598 union smb_open
*io
= async
->parms
;
599 union smb_handle
*file
;
601 req
->async_states
->status
= smb_raw_open_recv(c_req
, req
, io
);
602 SMB_OPEN_OUT_FILE(io
, file
);
603 f
->fnum
= file
->fnum
;
605 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
606 req
->async_states
->status
= ntvfs_handle_set_backend_data(f
->h
, cvfs
->ntvfs
, f
);
607 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
609 DLIST_ADD(cvfs
->files
, f
);
611 req
->async_states
->send_fn(req
);
617 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
618 struct ntvfs_request
*req
, union smb_open
*io
)
620 struct cvfs_private
*p
= ntvfs
->private_data
;
621 struct smbcli_request
*c_req
;
622 struct ntvfs_handle
*h
;
628 if (io
->generic
.level
!= RAW_OPEN_GENERIC
&&
630 return ntvfs_map_open(ntvfs
, req
, io
);
633 status
= ntvfs_handle_new(ntvfs
, req
, &h
);
634 NT_STATUS_NOT_OK_RETURN(status
);
636 f
= talloc_zero(h
, struct cvfs_file
);
637 NT_STATUS_HAVE_NO_MEMORY(f
);
640 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
641 union smb_handle
*file
;
643 status
= smb_raw_open(p
->tree
, req
, io
);
644 NT_STATUS_NOT_OK_RETURN(status
);
646 SMB_OPEN_OUT_FILE(io
, file
);
647 f
->fnum
= file
->fnum
;
649 status
= ntvfs_handle_set_backend_data(f
->h
, p
->ntvfs
, f
);
650 NT_STATUS_NOT_OK_RETURN(status
);
652 DLIST_ADD(p
->files
, f
);
657 c_req
= smb_raw_open_send(p
->tree
, io
);
659 ASYNC_RECV_TAIL_F(io
, async_open
, f
);
665 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
666 struct ntvfs_request
*req
, union smb_mkdir
*md
)
668 struct cvfs_private
*p
= ntvfs
->private_data
;
669 struct smbcli_request
*c_req
;
673 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
674 return smb_raw_mkdir(p
->tree
, md
);
677 c_req
= smb_raw_mkdir_send(p
->tree
, md
);
685 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
686 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
688 struct cvfs_private
*p
= ntvfs
->private_data
;
689 struct smbcli_request
*c_req
;
693 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
694 return smb_raw_rmdir(p
->tree
, rd
);
696 c_req
= smb_raw_rmdir_send(p
->tree
, rd
);
702 rename a set of files
704 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
705 struct ntvfs_request
*req
, union smb_rename
*ren
)
707 struct cvfs_private
*p
= ntvfs
->private_data
;
708 struct smbcli_request
*c_req
;
712 if (ren
->nttrans
.level
== RAW_RENAME_NTTRANS
) {
714 f
= ntvfs_handle_get_backend_data(ren
->nttrans
.in
.file
.ntvfs
, ntvfs
);
715 if (!f
) return NT_STATUS_INVALID_HANDLE
;
716 ren
->nttrans
.in
.file
.fnum
= f
->fnum
;
719 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
720 return smb_raw_rename(p
->tree
, ren
);
723 c_req
= smb_raw_rename_send(p
->tree
, ren
);
731 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
732 struct ntvfs_request
*req
, struct smb_copy
*cp
)
734 return NT_STATUS_NOT_SUPPORTED
;
738 a handler for async read replies
740 static void async_read(struct smbcli_request
*c_req
)
742 struct async_info
*async
= c_req
->async
.private_data
;
743 struct ntvfs_request
*req
= async
->req
;
744 req
->async_states
->status
= smb_raw_read_recv(c_req
, async
->parms
);
746 req
->async_states
->send_fn(req
);
752 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
753 struct ntvfs_request
*req
, union smb_read
*io
)
755 struct cvfs_private
*p
= ntvfs
->private_data
;
756 struct smbcli_request
*c_req
;
760 if (io
->generic
.level
!= RAW_READ_GENERIC
&&
762 return ntvfs_map_read(ntvfs
, req
, io
);
767 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
768 return smb_raw_read(p
->tree
, io
);
771 c_req
= smb_raw_read_send(p
->tree
, io
);
773 ASYNC_RECV_TAIL(io
, async_read
);
777 a handler for async write replies
779 static void async_write(struct smbcli_request
*c_req
)
781 struct async_info
*async
= c_req
->async
.private_data
;
782 struct ntvfs_request
*req
= async
->req
;
783 req
->async_states
->status
= smb_raw_write_recv(c_req
, async
->parms
);
785 req
->async_states
->send_fn(req
);
791 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
792 struct ntvfs_request
*req
, union smb_write
*io
)
794 struct cvfs_private
*p
= ntvfs
->private_data
;
795 struct smbcli_request
*c_req
;
799 if (io
->generic
.level
!= RAW_WRITE_GENERIC
&&
801 return ntvfs_map_write(ntvfs
, req
, io
);
805 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
806 return smb_raw_write(p
->tree
, io
);
809 c_req
= smb_raw_write_send(p
->tree
, io
);
811 ASYNC_RECV_TAIL(io
, async_write
);
815 a handler for async seek replies
817 static void async_seek(struct smbcli_request
*c_req
)
819 struct async_info
*async
= c_req
->async
.private_data
;
820 struct ntvfs_request
*req
= async
->req
;
821 req
->async_states
->status
= smb_raw_seek_recv(c_req
, async
->parms
);
823 req
->async_states
->send_fn(req
);
829 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
830 struct ntvfs_request
*req
,
833 struct cvfs_private
*p
= ntvfs
->private_data
;
834 struct smbcli_request
*c_req
;
838 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
839 return smb_raw_seek(p
->tree
, io
);
842 c_req
= smb_raw_seek_send(p
->tree
, io
);
844 ASYNC_RECV_TAIL(io
, async_seek
);
850 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
851 struct ntvfs_request
*req
,
854 struct cvfs_private
*p
= ntvfs
->private_data
;
855 struct smbcli_request
*c_req
;
858 switch (io
->generic
.level
) {
859 case RAW_FLUSH_FLUSH
:
863 io
->generic
.in
.file
.fnum
= 0xFFFF;
866 return NT_STATUS_INVALID_LEVEL
;
869 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
870 return smb_raw_flush(p
->tree
, io
);
873 c_req
= smb_raw_flush_send(p
->tree
, io
);
881 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
882 struct ntvfs_request
*req
, union smb_close
*io
)
884 struct cvfs_private
*p
= ntvfs
->private_data
;
885 struct smbcli_request
*c_req
;
891 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
&&
893 return ntvfs_map_close(ntvfs
, req
, io
);
896 if (io
->generic
.level
== RAW_CLOSE_GENERIC
) {
898 io2
.close
.level
= RAW_CLOSE_CLOSE
;
899 io2
.close
.in
.file
= io
->generic
.in
.file
;
900 io2
.close
.in
.write_time
= io
->generic
.in
.write_time
;
905 /* Note, we aren't free-ing f, or it's h here. Should we?
906 even if file-close fails, we'll remove it from the list,
907 what else would we do? Maybe we should not remove until
908 after the proxied call completes? */
909 DLIST_REMOVE(p
->files
, f
);
911 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
912 return smb_raw_close(p
->tree
, io
);
915 c_req
= smb_raw_close_send(p
->tree
, io
);
921 exit - closing files open by the pid
923 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
924 struct ntvfs_request
*req
)
926 struct cvfs_private
*p
= ntvfs
->private_data
;
927 struct smbcli_request
*c_req
;
931 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
932 return smb_raw_exit(p
->tree
->session
);
935 c_req
= smb_raw_exit_send(p
->tree
->session
);
941 logoff - closing files open by the user
943 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
944 struct ntvfs_request
*req
)
946 /* we can't do this right in the cifs backend .... */
951 setup for an async call - nothing to do yet
953 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
954 struct ntvfs_request
*req
,
963 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
964 struct ntvfs_request
*req
)
966 struct cvfs_private
*p
= ntvfs
->private_data
;
967 struct async_info
*a
;
969 /* find the matching request */
970 for (a
=p
->pending
;a
;a
=a
->next
) {
977 return NT_STATUS_INVALID_PARAMETER
;
980 return smb_raw_ntcancel(a
->c_req
);
986 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
987 struct ntvfs_request
*req
, union smb_lock
*io
)
989 struct cvfs_private
*p
= ntvfs
->private_data
;
990 struct smbcli_request
*c_req
;
994 if (io
->generic
.level
!= RAW_LOCK_GENERIC
&&
996 return ntvfs_map_lock(ntvfs
, req
, io
);
1000 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1001 return smb_raw_lock(p
->tree
, io
);
1004 c_req
= smb_raw_lock_send(p
->tree
, io
);
1009 set info on a open file
1011 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
1012 struct ntvfs_request
*req
,
1013 union smb_setfileinfo
*io
)
1015 struct cvfs_private
*p
= ntvfs
->private_data
;
1016 struct smbcli_request
*c_req
;
1020 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1021 return smb_raw_setfileinfo(p
->tree
, io
);
1023 c_req
= smb_raw_setfileinfo_send(p
->tree
, io
);
1030 a handler for async fsinfo replies
1032 static void async_fsinfo(struct smbcli_request
*c_req
)
1034 struct async_info
*async
= c_req
->async
.private_data
;
1035 struct ntvfs_request
*req
= async
->req
;
1036 req
->async_states
->status
= smb_raw_fsinfo_recv(c_req
, req
, async
->parms
);
1038 req
->async_states
->send_fn(req
);
1042 return filesystem space info
1044 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
1045 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
1047 struct cvfs_private
*p
= ntvfs
->private_data
;
1048 struct smbcli_request
*c_req
;
1052 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1053 return smb_raw_fsinfo(p
->tree
, req
, fs
);
1056 c_req
= smb_raw_fsinfo_send(p
->tree
, req
, fs
);
1058 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
1062 return print queue info
1064 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
1065 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
1067 return NT_STATUS_NOT_SUPPORTED
;
1071 list files in a directory matching a wildcard pattern
1073 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
1074 struct ntvfs_request
*req
, union smb_search_first
*io
,
1075 void *search_private
,
1076 bool (*callback
)(void *, const union smb_search_data
*))
1078 struct cvfs_private
*p
= ntvfs
->private_data
;
1082 return smb_raw_search_first(p
->tree
, req
, io
, search_private
, callback
);
1085 /* continue a search */
1086 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
1087 struct ntvfs_request
*req
, union smb_search_next
*io
,
1088 void *search_private
,
1089 bool (*callback
)(void *, const union smb_search_data
*))
1091 struct cvfs_private
*p
= ntvfs
->private_data
;
1095 return smb_raw_search_next(p
->tree
, req
, io
, search_private
, callback
);
1098 /* close a search */
1099 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
1100 struct ntvfs_request
*req
, union smb_search_close
*io
)
1102 struct cvfs_private
*p
= ntvfs
->private_data
;
1106 return smb_raw_search_close(p
->tree
, io
);
1110 a handler for async trans2 replies
1112 static void async_trans2(struct smbcli_request
*c_req
)
1114 struct async_info
*async
= c_req
->async
.private_data
;
1115 struct ntvfs_request
*req
= async
->req
;
1116 req
->async_states
->status
= smb_raw_trans2_recv(c_req
, req
, async
->parms
);
1118 req
->async_states
->send_fn(req
);
1122 static NTSTATUS
cvfs_trans2(struct ntvfs_module_context
*ntvfs
,
1123 struct ntvfs_request
*req
,
1124 struct smb_trans2
*trans2
)
1126 struct cvfs_private
*p
= ntvfs
->private_data
;
1127 struct smbcli_request
*c_req
;
1129 if (p
->map_trans2
) {
1130 return NT_STATUS_NOT_IMPLEMENTED
;
1135 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1136 return smb_raw_trans2(p
->tree
, req
, trans2
);
1139 c_req
= smb_raw_trans2_send(p
->tree
, trans2
);
1141 ASYNC_RECV_TAIL(trans2
, async_trans2
);
1145 /* SMBtrans - not used on file shares */
1146 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
1147 struct ntvfs_request
*req
,
1148 struct smb_trans2
*trans2
)
1150 return NT_STATUS_ACCESS_DENIED
;
1154 a handler for async change notify replies
1156 static void async_changenotify(struct smbcli_request
*c_req
)
1158 struct async_info
*async
= c_req
->async
.private_data
;
1159 struct ntvfs_request
*req
= async
->req
;
1160 req
->async_states
->status
= smb_raw_changenotify_recv(c_req
, req
, async
->parms
);
1162 req
->async_states
->send_fn(req
);
1165 /* change notify request - always async */
1166 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
1167 struct ntvfs_request
*req
,
1168 union smb_notify
*io
)
1170 struct cvfs_private
*p
= ntvfs
->private_data
;
1171 struct smbcli_request
*c_req
;
1172 int saved_timeout
= p
->transport
->options
.request_timeout
;
1173 struct cvfs_file
*f
;
1175 if (io
->nttrans
.level
!= RAW_NOTIFY_NTTRANS
) {
1176 return NT_STATUS_NOT_IMPLEMENTED
;
1181 f
= ntvfs_handle_get_backend_data(io
->nttrans
.in
.file
.ntvfs
, ntvfs
);
1182 if (!f
) return NT_STATUS_INVALID_HANDLE
;
1183 io
->nttrans
.in
.file
.fnum
= f
->fnum
;
1185 /* this request doesn't make sense unless its async */
1186 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1187 return NT_STATUS_INVALID_PARAMETER
;
1190 /* we must not timeout on notify requests - they wait
1192 p
->transport
->options
.request_timeout
= 0;
1194 c_req
= smb_raw_changenotify_send(p
->tree
, io
);
1196 p
->transport
->options
.request_timeout
= saved_timeout
;
1198 ASYNC_RECV_TAIL(io
, async_changenotify
);
1202 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1204 NTSTATUS
ntvfs_cifs_init(void)
1207 struct ntvfs_ops ops
;
1208 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
1212 /* fill in the name and type */
1214 ops
.type
= NTVFS_DISK
;
1216 /* fill in all the operations */
1217 ops
.connect_fn
= cvfs_connect
;
1218 ops
.disconnect_fn
= cvfs_disconnect
;
1219 ops
.unlink_fn
= cvfs_unlink
;
1220 ops
.chkpath_fn
= cvfs_chkpath
;
1221 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
1222 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
1223 ops
.open_fn
= cvfs_open
;
1224 ops
.mkdir_fn
= cvfs_mkdir
;
1225 ops
.rmdir_fn
= cvfs_rmdir
;
1226 ops
.rename_fn
= cvfs_rename
;
1227 ops
.copy_fn
= cvfs_copy
;
1228 ops
.ioctl_fn
= cvfs_ioctl
;
1229 ops
.read_fn
= cvfs_read
;
1230 ops
.write_fn
= cvfs_write
;
1231 ops
.seek_fn
= cvfs_seek
;
1232 ops
.flush_fn
= cvfs_flush
;
1233 ops
.close_fn
= cvfs_close
;
1234 ops
.exit_fn
= cvfs_exit
;
1235 ops
.lock_fn
= cvfs_lock
;
1236 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
1237 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
1238 ops
.fsinfo_fn
= cvfs_fsinfo
;
1239 ops
.lpq_fn
= cvfs_lpq
;
1240 ops
.search_first_fn
= cvfs_search_first
;
1241 ops
.search_next_fn
= cvfs_search_next
;
1242 ops
.search_close_fn
= cvfs_search_close
;
1243 ops
.trans_fn
= cvfs_trans
;
1244 ops
.logoff_fn
= cvfs_logoff
;
1245 ops
.async_setup_fn
= cvfs_async_setup
;
1246 ops
.cancel_fn
= cvfs_cancel
;
1247 ops
.notify_fn
= cvfs_notify
;
1248 ops
.trans2_fn
= cvfs_trans2
;
1250 /* register ourselves with the NTVFS subsystem. We register
1251 under the name 'cifs'. */
1252 ret
= ntvfs_register(&ops
, &vers
);
1254 if (!NT_STATUS_IS_OK(ret
)) {
1255 DEBUG(0,("Failed to register CIFS backend!\n"));