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
;
159 switch (tcon
->generic
.level
) {
161 sharename
= tcon
->tcon
.in
.service
;
164 sharename
= tcon
->tconx
.in
.path
;
167 sharename
= tcon
->smb2
.in
.path
;
170 return NT_STATUS_INVALID_LEVEL
;
173 if (strncmp(sharename
, "\\\\", 2) == 0) {
174 char *str
= strchr(sharename
+2, '\\');
180 /* Here we need to determine which server to connect to.
181 * For now we use parametric options, type cifs.
182 * Later we will use security=server and auth_server.c.
184 host
= share_string_option(scfg
, CIFS_SERVER
, NULL
);
185 user
= share_string_option(scfg
, CIFS_USER
, NULL
);
186 pass
= share_string_option(scfg
, CIFS_PASSWORD
, NULL
);
187 domain
= share_string_option(scfg
, CIFS_DOMAIN
, NULL
);
188 remote_share
= share_string_option(scfg
, CIFS_SHARE
, NULL
);
190 remote_share
= sharename
;
193 machine_account
= share_bool_option(scfg
, CIFS_USE_MACHINE_ACCT
, CIFS_USE_MACHINE_ACCT_DEFAULT
);
194 s4u2proxy
= share_bool_option(scfg
, CIFS_USE_S4U2PROXY
, CIFS_USE_S4U2PROXY_DEFAULT
);
196 p
= talloc_zero(ntvfs
, struct cvfs_private
);
198 return NT_STATUS_NO_MEMORY
;
201 ntvfs
->private_data
= p
;
204 DEBUG(1,("CIFS backend: You must supply server\n"));
205 return NT_STATUS_INVALID_PARAMETER
;
209 DEBUG(5, ("CIFS backend: Using specified password\n"));
210 credentials
= cli_credentials_init(p
);
212 return NT_STATUS_NO_MEMORY
;
214 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
215 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
217 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
219 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
220 } else if (machine_account
) {
221 DEBUG(5, ("CIFS backend: Using machine account\n"));
222 credentials
= cli_credentials_init(p
);
223 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
225 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
227 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
228 if (!NT_STATUS_IS_OK(status
)) {
231 } else if (req
->session_info
->credentials
) {
232 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
233 credentials
= req
->session_info
->credentials
;
234 } else if (s4u2proxy
) {
235 struct ccache_container
*ccc
= NULL
;
236 const char *err_str
= NULL
;
238 char *impersonate_principal
;
240 char *target_service
;
242 impersonate_principal
= talloc_asprintf(req
, "%s@%s",
243 req
->session_info
->info
->account_name
,
244 req
->session_info
->info
->domain_name
);
246 self_service
= talloc_asprintf(req
, "cifs/%s",
247 lpcfg_netbios_name(ntvfs
->ctx
->lp_ctx
));
249 target_service
= talloc_asprintf(req
, "cifs/%s", host
);
251 DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
253 credentials
= cli_credentials_init(p
);
254 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
256 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
258 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
259 if (!NT_STATUS_IS_OK(status
)) {
262 cli_credentials_invalidate_ccache(credentials
, CRED_SPECIFIED
);
263 cli_credentials_set_impersonate_principal(credentials
,
264 impersonate_principal
,
266 cli_credentials_set_target_service(credentials
, target_service
);
267 ret
= cli_credentials_get_ccache(credentials
,
268 ntvfs
->ctx
->event_ctx
,
273 status
= NT_STATUS_CROSSREALM_DELEGATION_FAILURE
;
274 DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n",
275 ret
, err_str
, nt_errstr(status
)));
280 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
281 return NT_STATUS_INTERNAL_ERROR
;
284 /* connect to the server, using the smbd event context */
285 io
.in
.dest_host
= host
;
286 io
.in
.dest_ports
= lpcfg_smb_ports(ntvfs
->ctx
->lp_ctx
);
287 io
.in
.socket_options
= lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
);
288 io
.in
.called_name
= host
;
289 io
.in
.credentials
= credentials
;
290 io
.in
.fallback_to_anonymous
= false;
291 io
.in
.workgroup
= lpcfg_workgroup(ntvfs
->ctx
->lp_ctx
);
292 io
.in
.service
= remote_share
;
293 io
.in
.service_type
= "?????";
294 io
.in
.gensec_settings
= lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
);
295 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.options
);
296 lpcfg_smbcli_session_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.session_options
);
298 if (!(ntvfs
->ctx
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
)) {
299 io
.in
.options
.use_level2_oplocks
= false;
302 creq
= smb_composite_connect_send(&io
, p
,
303 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
304 ntvfs
->ctx
->event_ctx
);
305 status
= smb_composite_connect_recv(creq
, p
);
306 NT_STATUS_NOT_OK_RETURN(status
);
308 p
->tree
= io
.out
.tree
;
310 p
->transport
= p
->tree
->session
->transport
;
314 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
315 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
316 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
317 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
319 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
320 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
321 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
324 /* we need to receive oplock break requests from the server */
325 smbcli_oplock_handler(p
->transport
, oplock_handler
, p
);
327 p
->map_generic
= share_bool_option(scfg
, CIFS_MAP_GENERIC
, CIFS_MAP_GENERIC_DEFAULT
);
329 p
->map_trans2
= share_bool_option(scfg
, CIFS_MAP_TRANS2
, CIFS_MAP_TRANS2_DEFAULT
);
335 disconnect from a share
337 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
339 struct cvfs_private
*p
= ntvfs
->private_data
;
340 struct async_info
*a
, *an
;
342 /* first cleanup pending requests */
343 for (a
=p
->pending
; a
; a
= an
) {
345 smbcli_request_destroy(a
->c_req
);
350 ntvfs
->private_data
= NULL
;
356 destroy an async info structure
358 static int async_info_destructor(struct async_info
*async
)
360 DLIST_REMOVE(async
->cvfs
->pending
, async
);
365 a handler for simple async replies
366 this handler can only be used for functions that don't return any
367 parameters (those that just return a status code)
369 static void async_simple(struct smbcli_request
*c_req
)
371 struct async_info
*async
= c_req
->async
.private_data
;
372 struct ntvfs_request
*req
= async
->req
;
373 req
->async_states
->status
= smbcli_request_simple_recv(c_req
);
375 req
->async_states
->send_fn(req
);
379 /* save some typing for the simple functions */
380 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
381 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
383 struct async_info *async; \
384 async = talloc(req, struct async_info); \
385 if (!async) return NT_STATUS_NO_MEMORY; \
390 async->c_req = c_req; \
391 DLIST_ADD(p->pending, async); \
392 c_req->async.private_data = async; \
393 talloc_set_destructor(async, async_info_destructor); \
395 c_req->async.fn = async_fn; \
396 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
397 return NT_STATUS_OK; \
400 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
402 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
405 delete a file - the dirtype specifies the file types to include in the search.
406 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
408 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
409 struct ntvfs_request
*req
, union smb_unlink
*unl
)
411 struct cvfs_private
*p
= ntvfs
->private_data
;
412 struct smbcli_request
*c_req
;
416 /* see if the front end will allow us to perform this
417 function asynchronously. */
418 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
419 return smb_raw_unlink(p
->tree
, unl
);
422 c_req
= smb_raw_unlink_send(p
->tree
, unl
);
428 a handler for async ioctl replies
430 static void async_ioctl(struct smbcli_request
*c_req
)
432 struct async_info
*async
= c_req
->async
.private_data
;
433 struct ntvfs_request
*req
= async
->req
;
434 req
->async_states
->status
= smb_raw_ioctl_recv(c_req
, req
, async
->parms
);
436 req
->async_states
->send_fn(req
);
442 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
443 struct ntvfs_request
*req
, union smb_ioctl
*io
)
445 struct cvfs_private
*p
= ntvfs
->private_data
;
446 struct smbcli_request
*c_req
;
450 /* see if the front end will allow us to perform this
451 function asynchronously. */
452 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
453 return smb_raw_ioctl(p
->tree
, req
, io
);
456 c_req
= smb_raw_ioctl_send(p
->tree
, io
);
458 ASYNC_RECV_TAIL(io
, async_ioctl
);
462 check if a directory exists
464 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
465 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
467 struct cvfs_private
*p
= ntvfs
->private_data
;
468 struct smbcli_request
*c_req
;
472 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
473 return smb_raw_chkpath(p
->tree
, cp
);
476 c_req
= smb_raw_chkpath_send(p
->tree
, cp
);
482 a handler for async qpathinfo replies
484 static void async_qpathinfo(struct smbcli_request
*c_req
)
486 struct async_info
*async
= c_req
->async
.private_data
;
487 struct ntvfs_request
*req
= async
->req
;
488 req
->async_states
->status
= smb_raw_pathinfo_recv(c_req
, req
, async
->parms
);
490 req
->async_states
->send_fn(req
);
494 return info on a pathname
496 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
497 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
499 struct cvfs_private
*p
= ntvfs
->private_data
;
500 struct smbcli_request
*c_req
;
504 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
505 return smb_raw_pathinfo(p
->tree
, req
, info
);
508 c_req
= smb_raw_pathinfo_send(p
->tree
, info
);
510 ASYNC_RECV_TAIL(info
, async_qpathinfo
);
514 a handler for async qfileinfo replies
516 static void async_qfileinfo(struct smbcli_request
*c_req
)
518 struct async_info
*async
= c_req
->async
.private_data
;
519 struct ntvfs_request
*req
= async
->req
;
520 req
->async_states
->status
= smb_raw_fileinfo_recv(c_req
, req
, async
->parms
);
522 req
->async_states
->send_fn(req
);
526 query info on a open file
528 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
529 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
531 struct cvfs_private
*p
= ntvfs
->private_data
;
532 struct smbcli_request
*c_req
;
536 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
537 return smb_raw_fileinfo(p
->tree
, req
, io
);
540 c_req
= smb_raw_fileinfo_send(p
->tree
, io
);
542 ASYNC_RECV_TAIL(io
, async_qfileinfo
);
547 set info on a pathname
549 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
550 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
552 struct cvfs_private
*p
= ntvfs
->private_data
;
553 struct smbcli_request
*c_req
;
557 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
558 return smb_raw_setpathinfo(p
->tree
, st
);
561 c_req
= smb_raw_setpathinfo_send(p
->tree
, st
);
568 a handler for async open replies
570 static void async_open(struct smbcli_request
*c_req
)
572 struct async_info
*async
= c_req
->async
.private_data
;
573 struct cvfs_private
*cvfs
= async
->cvfs
;
574 struct ntvfs_request
*req
= async
->req
;
575 struct cvfs_file
*f
= async
->f
;
576 union smb_open
*io
= async
->parms
;
577 union smb_handle
*file
;
579 req
->async_states
->status
= smb_raw_open_recv(c_req
, req
, io
);
580 SMB_OPEN_OUT_FILE(io
, file
);
581 f
->fnum
= file
->fnum
;
583 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
584 req
->async_states
->status
= ntvfs_handle_set_backend_data(f
->h
, cvfs
->ntvfs
, f
);
585 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
587 DLIST_ADD(cvfs
->files
, f
);
589 req
->async_states
->send_fn(req
);
595 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
596 struct ntvfs_request
*req
, union smb_open
*io
)
598 struct cvfs_private
*p
= ntvfs
->private_data
;
599 struct smbcli_request
*c_req
;
600 struct ntvfs_handle
*h
;
606 if (io
->generic
.level
!= RAW_OPEN_GENERIC
&&
608 return ntvfs_map_open(ntvfs
, req
, io
);
611 status
= ntvfs_handle_new(ntvfs
, req
, &h
);
612 NT_STATUS_NOT_OK_RETURN(status
);
614 f
= talloc_zero(h
, struct cvfs_file
);
615 NT_STATUS_HAVE_NO_MEMORY(f
);
618 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
619 union smb_handle
*file
;
621 status
= smb_raw_open(p
->tree
, req
, io
);
622 NT_STATUS_NOT_OK_RETURN(status
);
624 SMB_OPEN_OUT_FILE(io
, file
);
625 f
->fnum
= file
->fnum
;
627 status
= ntvfs_handle_set_backend_data(f
->h
, p
->ntvfs
, f
);
628 NT_STATUS_NOT_OK_RETURN(status
);
630 DLIST_ADD(p
->files
, f
);
635 c_req
= smb_raw_open_send(p
->tree
, io
);
637 ASYNC_RECV_TAIL_F(io
, async_open
, f
);
643 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
644 struct ntvfs_request
*req
, union smb_mkdir
*md
)
646 struct cvfs_private
*p
= ntvfs
->private_data
;
647 struct smbcli_request
*c_req
;
651 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
652 return smb_raw_mkdir(p
->tree
, md
);
655 c_req
= smb_raw_mkdir_send(p
->tree
, md
);
663 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
664 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
666 struct cvfs_private
*p
= ntvfs
->private_data
;
667 struct smbcli_request
*c_req
;
671 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
672 return smb_raw_rmdir(p
->tree
, rd
);
674 c_req
= smb_raw_rmdir_send(p
->tree
, rd
);
680 rename a set of files
682 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
683 struct ntvfs_request
*req
, union smb_rename
*ren
)
685 struct cvfs_private
*p
= ntvfs
->private_data
;
686 struct smbcli_request
*c_req
;
690 if (ren
->nttrans
.level
== RAW_RENAME_NTTRANS
) {
692 f
= ntvfs_handle_get_backend_data(ren
->nttrans
.in
.file
.ntvfs
, ntvfs
);
693 if (!f
) return NT_STATUS_INVALID_HANDLE
;
694 ren
->nttrans
.in
.file
.fnum
= f
->fnum
;
697 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
698 return smb_raw_rename(p
->tree
, ren
);
701 c_req
= smb_raw_rename_send(p
->tree
, ren
);
709 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
710 struct ntvfs_request
*req
, struct smb_copy
*cp
)
712 return NT_STATUS_NOT_SUPPORTED
;
716 a handler for async read replies
718 static void async_read(struct smbcli_request
*c_req
)
720 struct async_info
*async
= c_req
->async
.private_data
;
721 struct ntvfs_request
*req
= async
->req
;
722 req
->async_states
->status
= smb_raw_read_recv(c_req
, async
->parms
);
724 req
->async_states
->send_fn(req
);
730 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
731 struct ntvfs_request
*req
, union smb_read
*io
)
733 struct cvfs_private
*p
= ntvfs
->private_data
;
734 struct smbcli_request
*c_req
;
738 if (io
->generic
.level
!= RAW_READ_GENERIC
&&
740 return ntvfs_map_read(ntvfs
, req
, io
);
745 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
746 return smb_raw_read(p
->tree
, io
);
749 c_req
= smb_raw_read_send(p
->tree
, io
);
751 ASYNC_RECV_TAIL(io
, async_read
);
755 a handler for async write replies
757 static void async_write(struct smbcli_request
*c_req
)
759 struct async_info
*async
= c_req
->async
.private_data
;
760 struct ntvfs_request
*req
= async
->req
;
761 req
->async_states
->status
= smb_raw_write_recv(c_req
, async
->parms
);
763 req
->async_states
->send_fn(req
);
769 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
770 struct ntvfs_request
*req
, union smb_write
*io
)
772 struct cvfs_private
*p
= ntvfs
->private_data
;
773 struct smbcli_request
*c_req
;
777 if (io
->generic
.level
!= RAW_WRITE_GENERIC
&&
779 return ntvfs_map_write(ntvfs
, req
, io
);
783 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
784 return smb_raw_write(p
->tree
, io
);
787 c_req
= smb_raw_write_send(p
->tree
, io
);
789 ASYNC_RECV_TAIL(io
, async_write
);
793 a handler for async seek replies
795 static void async_seek(struct smbcli_request
*c_req
)
797 struct async_info
*async
= c_req
->async
.private_data
;
798 struct ntvfs_request
*req
= async
->req
;
799 req
->async_states
->status
= smb_raw_seek_recv(c_req
, async
->parms
);
801 req
->async_states
->send_fn(req
);
807 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
808 struct ntvfs_request
*req
,
811 struct cvfs_private
*p
= ntvfs
->private_data
;
812 struct smbcli_request
*c_req
;
816 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
817 return smb_raw_seek(p
->tree
, io
);
820 c_req
= smb_raw_seek_send(p
->tree
, io
);
822 ASYNC_RECV_TAIL(io
, async_seek
);
828 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
829 struct ntvfs_request
*req
,
832 struct cvfs_private
*p
= ntvfs
->private_data
;
833 struct smbcli_request
*c_req
;
836 switch (io
->generic
.level
) {
837 case RAW_FLUSH_FLUSH
:
841 io
->generic
.in
.file
.fnum
= 0xFFFF;
844 return NT_STATUS_INVALID_LEVEL
;
847 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
848 return smb_raw_flush(p
->tree
, io
);
851 c_req
= smb_raw_flush_send(p
->tree
, io
);
859 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
860 struct ntvfs_request
*req
, union smb_close
*io
)
862 struct cvfs_private
*p
= ntvfs
->private_data
;
863 struct smbcli_request
*c_req
;
869 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
&&
871 return ntvfs_map_close(ntvfs
, req
, io
);
874 if (io
->generic
.level
== RAW_CLOSE_GENERIC
) {
876 io2
.close
.level
= RAW_CLOSE_CLOSE
;
877 io2
.close
.in
.file
= io
->generic
.in
.file
;
878 io2
.close
.in
.write_time
= io
->generic
.in
.write_time
;
883 /* Note, we aren't free-ing f, or it's h here. Should we?
884 even if file-close fails, we'll remove it from the list,
885 what else would we do? Maybe we should not remove until
886 after the proxied call completes? */
887 DLIST_REMOVE(p
->files
, f
);
889 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
890 return smb_raw_close(p
->tree
, io
);
893 c_req
= smb_raw_close_send(p
->tree
, io
);
899 exit - closing files open by the pid
901 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
902 struct ntvfs_request
*req
)
904 struct cvfs_private
*p
= ntvfs
->private_data
;
905 struct smbcli_request
*c_req
;
909 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
910 return smb_raw_exit(p
->tree
->session
);
913 c_req
= smb_raw_exit_send(p
->tree
->session
);
919 logoff - closing files open by the user
921 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
922 struct ntvfs_request
*req
)
924 /* we can't do this right in the cifs backend .... */
929 setup for an async call - nothing to do yet
931 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
932 struct ntvfs_request
*req
,
941 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
942 struct ntvfs_request
*req
)
944 struct cvfs_private
*p
= ntvfs
->private_data
;
945 struct async_info
*a
;
947 /* find the matching request */
948 for (a
=p
->pending
;a
;a
=a
->next
) {
955 return NT_STATUS_INVALID_PARAMETER
;
958 return smb_raw_ntcancel(a
->c_req
);
964 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
965 struct ntvfs_request
*req
, union smb_lock
*io
)
967 struct cvfs_private
*p
= ntvfs
->private_data
;
968 struct smbcli_request
*c_req
;
972 if (io
->generic
.level
!= RAW_LOCK_GENERIC
&&
974 return ntvfs_map_lock(ntvfs
, req
, io
);
978 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
979 return smb_raw_lock(p
->tree
, io
);
982 c_req
= smb_raw_lock_send(p
->tree
, io
);
987 set info on a open file
989 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
990 struct ntvfs_request
*req
,
991 union smb_setfileinfo
*io
)
993 struct cvfs_private
*p
= ntvfs
->private_data
;
994 struct smbcli_request
*c_req
;
998 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
999 return smb_raw_setfileinfo(p
->tree
, io
);
1001 c_req
= smb_raw_setfileinfo_send(p
->tree
, io
);
1008 a handler for async fsinfo replies
1010 static void async_fsinfo(struct smbcli_request
*c_req
)
1012 struct async_info
*async
= c_req
->async
.private_data
;
1013 struct ntvfs_request
*req
= async
->req
;
1014 req
->async_states
->status
= smb_raw_fsinfo_recv(c_req
, req
, async
->parms
);
1016 req
->async_states
->send_fn(req
);
1020 return filesystem space info
1022 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
1023 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
1025 struct cvfs_private
*p
= ntvfs
->private_data
;
1026 struct smbcli_request
*c_req
;
1030 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1031 return smb_raw_fsinfo(p
->tree
, req
, fs
);
1034 c_req
= smb_raw_fsinfo_send(p
->tree
, req
, fs
);
1036 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
1040 return print queue info
1042 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
1043 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
1045 return NT_STATUS_NOT_SUPPORTED
;
1049 list files in a directory matching a wildcard pattern
1051 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
1052 struct ntvfs_request
*req
, union smb_search_first
*io
,
1053 void *search_private
,
1054 bool (*callback
)(void *, const union smb_search_data
*))
1056 struct cvfs_private
*p
= ntvfs
->private_data
;
1060 return smb_raw_search_first(p
->tree
, req
, io
, search_private
, callback
);
1063 /* continue a search */
1064 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
1065 struct ntvfs_request
*req
, union smb_search_next
*io
,
1066 void *search_private
,
1067 bool (*callback
)(void *, const union smb_search_data
*))
1069 struct cvfs_private
*p
= ntvfs
->private_data
;
1073 return smb_raw_search_next(p
->tree
, req
, io
, search_private
, callback
);
1076 /* close a search */
1077 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
1078 struct ntvfs_request
*req
, union smb_search_close
*io
)
1080 struct cvfs_private
*p
= ntvfs
->private_data
;
1084 return smb_raw_search_close(p
->tree
, io
);
1088 a handler for async trans2 replies
1090 static void async_trans2(struct smbcli_request
*c_req
)
1092 struct async_info
*async
= c_req
->async
.private_data
;
1093 struct ntvfs_request
*req
= async
->req
;
1094 req
->async_states
->status
= smb_raw_trans2_recv(c_req
, req
, async
->parms
);
1096 req
->async_states
->send_fn(req
);
1100 static NTSTATUS
cvfs_trans2(struct ntvfs_module_context
*ntvfs
,
1101 struct ntvfs_request
*req
,
1102 struct smb_trans2
*trans2
)
1104 struct cvfs_private
*p
= ntvfs
->private_data
;
1105 struct smbcli_request
*c_req
;
1107 if (p
->map_trans2
) {
1108 return NT_STATUS_NOT_IMPLEMENTED
;
1113 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1114 return smb_raw_trans2(p
->tree
, req
, trans2
);
1117 c_req
= smb_raw_trans2_send(p
->tree
, trans2
);
1119 ASYNC_RECV_TAIL(trans2
, async_trans2
);
1123 /* SMBtrans - not used on file shares */
1124 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
1125 struct ntvfs_request
*req
,
1126 struct smb_trans2
*trans2
)
1128 return NT_STATUS_ACCESS_DENIED
;
1132 a handler for async change notify replies
1134 static void async_changenotify(struct smbcli_request
*c_req
)
1136 struct async_info
*async
= c_req
->async
.private_data
;
1137 struct ntvfs_request
*req
= async
->req
;
1138 req
->async_states
->status
= smb_raw_changenotify_recv(c_req
, req
, async
->parms
);
1140 req
->async_states
->send_fn(req
);
1143 /* change notify request - always async */
1144 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
1145 struct ntvfs_request
*req
,
1146 union smb_notify
*io
)
1148 struct cvfs_private
*p
= ntvfs
->private_data
;
1149 struct smbcli_request
*c_req
;
1150 int saved_timeout
= p
->transport
->options
.request_timeout
;
1151 struct cvfs_file
*f
;
1153 if (io
->nttrans
.level
!= RAW_NOTIFY_NTTRANS
) {
1154 return NT_STATUS_NOT_IMPLEMENTED
;
1159 f
= ntvfs_handle_get_backend_data(io
->nttrans
.in
.file
.ntvfs
, ntvfs
);
1160 if (!f
) return NT_STATUS_INVALID_HANDLE
;
1161 io
->nttrans
.in
.file
.fnum
= f
->fnum
;
1163 /* this request doesn't make sense unless its async */
1164 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1165 return NT_STATUS_INVALID_PARAMETER
;
1168 /* we must not timeout on notify requests - they wait
1170 p
->transport
->options
.request_timeout
= 0;
1172 c_req
= smb_raw_changenotify_send(p
->tree
, io
);
1174 p
->transport
->options
.request_timeout
= saved_timeout
;
1176 ASYNC_RECV_TAIL(io
, async_changenotify
);
1180 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1182 NTSTATUS
ntvfs_cifs_init(void)
1185 struct ntvfs_ops ops
;
1186 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
1190 /* fill in the name and type */
1192 ops
.type
= NTVFS_DISK
;
1194 /* fill in all the operations */
1195 ops
.connect
= cvfs_connect
;
1196 ops
.disconnect
= cvfs_disconnect
;
1197 ops
.unlink
= cvfs_unlink
;
1198 ops
.chkpath
= cvfs_chkpath
;
1199 ops
.qpathinfo
= cvfs_qpathinfo
;
1200 ops
.setpathinfo
= cvfs_setpathinfo
;
1201 ops
.open
= cvfs_open
;
1202 ops
.mkdir
= cvfs_mkdir
;
1203 ops
.rmdir
= cvfs_rmdir
;
1204 ops
.rename
= cvfs_rename
;
1205 ops
.copy
= cvfs_copy
;
1206 ops
.ioctl
= cvfs_ioctl
;
1207 ops
.read
= cvfs_read
;
1208 ops
.write
= cvfs_write
;
1209 ops
.seek
= cvfs_seek
;
1210 ops
.flush
= cvfs_flush
;
1211 ops
.close
= cvfs_close
;
1212 ops
.exit
= cvfs_exit
;
1213 ops
.lock
= cvfs_lock
;
1214 ops
.setfileinfo
= cvfs_setfileinfo
;
1215 ops
.qfileinfo
= cvfs_qfileinfo
;
1216 ops
.fsinfo
= cvfs_fsinfo
;
1218 ops
.search_first
= cvfs_search_first
;
1219 ops
.search_next
= cvfs_search_next
;
1220 ops
.search_close
= cvfs_search_close
;
1221 ops
.trans
= cvfs_trans
;
1222 ops
.logoff
= cvfs_logoff
;
1223 ops
.async_setup
= cvfs_async_setup
;
1224 ops
.cancel
= cvfs_cancel
;
1225 ops
.notify
= cvfs_notify
;
1226 ops
.trans2
= cvfs_trans2
;
1228 /* register ourselves with the NTVFS subsystem. We register
1229 under the name 'cifs'. */
1230 ret
= ntvfs_register(&ops
, &vers
);
1232 if (!NT_STATUS_IS_OK(ret
)) {
1233 DEBUG(0,("Failed to register CIFS backend!\n"));