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(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
.existing_conn
= NULL
;
300 io
.in
.credentials
= credentials
;
301 io
.in
.fallback_to_anonymous
= false;
302 io
.in
.workgroup
= lpcfg_workgroup(ntvfs
->ctx
->lp_ctx
);
303 io
.in
.service
= remote_share
;
304 io
.in
.service_type
= "?????";
305 io
.in
.gensec_settings
= lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
);
306 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.options
);
307 lpcfg_smbcli_session_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.session_options
);
309 if (!(ntvfs
->ctx
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
)) {
310 io
.in
.options
.use_level2_oplocks
= false;
313 creq
= smb_composite_connect_send(&io
, p
,
314 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
315 ntvfs
->ctx
->event_ctx
);
316 status
= smb_composite_connect_recv(creq
, p
);
317 if (!NT_STATUS_IS_OK(status
)) {
321 p
->tree
= io
.out
.tree
;
323 p
->transport
= p
->tree
->session
->transport
;
327 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
328 if (ntvfs
->ctx
->fs_type
== NULL
) {
329 status
= NT_STATUS_NO_MEMORY
;
332 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
333 if (ntvfs
->ctx
->dev_type
== NULL
) {
334 status
= NT_STATUS_NO_MEMORY
;
338 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
339 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
340 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
343 /* we need to receive oplock break requests from the server */
344 smbcli_oplock_handler(p
->transport
, oplock_handler
, p
);
346 p
->map_generic
= share_bool_option(scfg
, CIFS_MAP_GENERIC
, CIFS_MAP_GENERIC_DEFAULT
);
348 p
->map_trans2
= share_bool_option(scfg
, CIFS_MAP_TRANS2
, CIFS_MAP_TRANS2_DEFAULT
);
350 status
= NT_STATUS_OK
;
353 TALLOC_FREE(tmp_ctx
);
358 disconnect from a share
360 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
362 struct cvfs_private
*p
= ntvfs
->private_data
;
363 struct async_info
*a
, *an
;
365 /* first cleanup pending requests */
366 for (a
=p
->pending
; a
; a
= an
) {
368 smbcli_request_destroy(a
->c_req
);
373 ntvfs
->private_data
= NULL
;
379 destroy an async info structure
381 static int async_info_destructor(struct async_info
*async
)
383 DLIST_REMOVE(async
->cvfs
->pending
, async
);
388 a handler for simple async replies
389 this handler can only be used for functions that don't return any
390 parameters (those that just return a status code)
392 static void async_simple(struct smbcli_request
*c_req
)
394 struct async_info
*async
= c_req
->async
.private_data
;
395 struct ntvfs_request
*req
= async
->req
;
396 req
->async_states
->status
= smbcli_request_simple_recv(c_req
);
398 req
->async_states
->send_fn(req
);
402 /* save some typing for the simple functions */
403 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
404 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
406 struct async_info *async; \
407 async = talloc(req, struct async_info); \
408 if (!async) return NT_STATUS_NO_MEMORY; \
413 async->c_req = c_req; \
414 DLIST_ADD(p->pending, async); \
415 c_req->async.private_data = async; \
416 talloc_set_destructor(async, async_info_destructor); \
418 c_req->async.fn = async_fn; \
419 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
420 return NT_STATUS_OK; \
423 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
425 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
428 delete a file - the dirtype specifies the file types to include in the search.
429 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
431 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
432 struct ntvfs_request
*req
, union smb_unlink
*unl
)
434 struct cvfs_private
*p
= ntvfs
->private_data
;
435 struct smbcli_request
*c_req
;
439 /* see if the front end will allow us to perform this
440 function asynchronously. */
441 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
442 return smb_raw_unlink(p
->tree
, unl
);
445 c_req
= smb_raw_unlink_send(p
->tree
, unl
);
451 a handler for async ioctl replies
453 static void async_ioctl(struct smbcli_request
*c_req
)
455 struct async_info
*async
= c_req
->async
.private_data
;
456 struct ntvfs_request
*req
= async
->req
;
457 req
->async_states
->status
= smb_raw_ioctl_recv(c_req
, req
, async
->parms
);
459 req
->async_states
->send_fn(req
);
465 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
466 struct ntvfs_request
*req
, union smb_ioctl
*io
)
468 struct cvfs_private
*p
= ntvfs
->private_data
;
469 struct smbcli_request
*c_req
;
473 /* see if the front end will allow us to perform this
474 function asynchronously. */
475 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
476 return smb_raw_ioctl(p
->tree
, req
, io
);
479 c_req
= smb_raw_ioctl_send(p
->tree
, io
);
481 ASYNC_RECV_TAIL(io
, async_ioctl
);
485 check if a directory exists
487 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
488 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
490 struct cvfs_private
*p
= ntvfs
->private_data
;
491 struct smbcli_request
*c_req
;
495 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
496 return smb_raw_chkpath(p
->tree
, cp
);
499 c_req
= smb_raw_chkpath_send(p
->tree
, cp
);
505 a handler for async qpathinfo replies
507 static void async_qpathinfo(struct smbcli_request
*c_req
)
509 struct async_info
*async
= c_req
->async
.private_data
;
510 struct ntvfs_request
*req
= async
->req
;
511 req
->async_states
->status
= smb_raw_pathinfo_recv(c_req
, req
, async
->parms
);
513 req
->async_states
->send_fn(req
);
517 return info on a pathname
519 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
520 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
522 struct cvfs_private
*p
= ntvfs
->private_data
;
523 struct smbcli_request
*c_req
;
527 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
528 return smb_raw_pathinfo(p
->tree
, req
, info
);
531 c_req
= smb_raw_pathinfo_send(p
->tree
, info
);
533 ASYNC_RECV_TAIL(info
, async_qpathinfo
);
537 a handler for async qfileinfo replies
539 static void async_qfileinfo(struct smbcli_request
*c_req
)
541 struct async_info
*async
= c_req
->async
.private_data
;
542 struct ntvfs_request
*req
= async
->req
;
543 req
->async_states
->status
= smb_raw_fileinfo_recv(c_req
, req
, async
->parms
);
545 req
->async_states
->send_fn(req
);
549 query info on a open file
551 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
552 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
554 struct cvfs_private
*p
= ntvfs
->private_data
;
555 struct smbcli_request
*c_req
;
559 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
560 return smb_raw_fileinfo(p
->tree
, req
, io
);
563 c_req
= smb_raw_fileinfo_send(p
->tree
, io
);
565 ASYNC_RECV_TAIL(io
, async_qfileinfo
);
570 set info on a pathname
572 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
573 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
575 struct cvfs_private
*p
= ntvfs
->private_data
;
576 struct smbcli_request
*c_req
;
580 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
581 return smb_raw_setpathinfo(p
->tree
, st
);
584 c_req
= smb_raw_setpathinfo_send(p
->tree
, st
);
591 a handler for async open replies
593 static void async_open(struct smbcli_request
*c_req
)
595 struct async_info
*async
= c_req
->async
.private_data
;
596 struct cvfs_private
*cvfs
= async
->cvfs
;
597 struct ntvfs_request
*req
= async
->req
;
598 struct cvfs_file
*f
= async
->f
;
599 union smb_open
*io
= async
->parms
;
600 union smb_handle
*file
;
602 req
->async_states
->status
= smb_raw_open_recv(c_req
, req
, io
);
603 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
);
648 f
->fnum
= file
->fnum
;
650 status
= ntvfs_handle_set_backend_data(f
->h
, p
->ntvfs
, f
);
651 NT_STATUS_NOT_OK_RETURN(status
);
653 DLIST_ADD(p
->files
, f
);
658 c_req
= smb_raw_open_send(p
->tree
, io
);
660 ASYNC_RECV_TAIL_F(io
, async_open
, f
);
666 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
667 struct ntvfs_request
*req
, union smb_mkdir
*md
)
669 struct cvfs_private
*p
= ntvfs
->private_data
;
670 struct smbcli_request
*c_req
;
674 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
675 return smb_raw_mkdir(p
->tree
, md
);
678 c_req
= smb_raw_mkdir_send(p
->tree
, md
);
686 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
687 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
689 struct cvfs_private
*p
= ntvfs
->private_data
;
690 struct smbcli_request
*c_req
;
694 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
695 return smb_raw_rmdir(p
->tree
, rd
);
697 c_req
= smb_raw_rmdir_send(p
->tree
, rd
);
703 rename a set of files
705 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
706 struct ntvfs_request
*req
, union smb_rename
*ren
)
708 struct cvfs_private
*p
= ntvfs
->private_data
;
709 struct smbcli_request
*c_req
;
713 if (ren
->nttrans
.level
== RAW_RENAME_NTTRANS
) {
715 f
= ntvfs_handle_get_backend_data(ren
->nttrans
.in
.file
.ntvfs
, ntvfs
);
716 if (!f
) return NT_STATUS_INVALID_HANDLE
;
717 ren
->nttrans
.in
.file
.fnum
= f
->fnum
;
720 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
721 return smb_raw_rename(p
->tree
, ren
);
724 c_req
= smb_raw_rename_send(p
->tree
, ren
);
732 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
733 struct ntvfs_request
*req
, struct smb_copy
*cp
)
735 return NT_STATUS_NOT_SUPPORTED
;
739 a handler for async read replies
741 static void async_read(struct smbcli_request
*c_req
)
743 struct async_info
*async
= c_req
->async
.private_data
;
744 struct ntvfs_request
*req
= async
->req
;
745 req
->async_states
->status
= smb_raw_read_recv(c_req
, async
->parms
);
747 req
->async_states
->send_fn(req
);
753 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
754 struct ntvfs_request
*req
, union smb_read
*io
)
756 struct cvfs_private
*p
= ntvfs
->private_data
;
757 struct smbcli_request
*c_req
;
761 if (io
->generic
.level
!= RAW_READ_GENERIC
&&
763 return ntvfs_map_read(ntvfs
, req
, io
);
768 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
769 return smb_raw_read(p
->tree
, io
);
772 c_req
= smb_raw_read_send(p
->tree
, io
);
774 ASYNC_RECV_TAIL(io
, async_read
);
778 a handler for async write replies
780 static void async_write(struct smbcli_request
*c_req
)
782 struct async_info
*async
= c_req
->async
.private_data
;
783 struct ntvfs_request
*req
= async
->req
;
784 req
->async_states
->status
= smb_raw_write_recv(c_req
, async
->parms
);
786 req
->async_states
->send_fn(req
);
792 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
793 struct ntvfs_request
*req
, union smb_write
*io
)
795 struct cvfs_private
*p
= ntvfs
->private_data
;
796 struct smbcli_request
*c_req
;
800 if (io
->generic
.level
!= RAW_WRITE_GENERIC
&&
802 return ntvfs_map_write(ntvfs
, req
, io
);
806 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
807 return smb_raw_write(p
->tree
, io
);
810 c_req
= smb_raw_write_send(p
->tree
, io
);
812 ASYNC_RECV_TAIL(io
, async_write
);
816 a handler for async seek replies
818 static void async_seek(struct smbcli_request
*c_req
)
820 struct async_info
*async
= c_req
->async
.private_data
;
821 struct ntvfs_request
*req
= async
->req
;
822 req
->async_states
->status
= smb_raw_seek_recv(c_req
, async
->parms
);
824 req
->async_states
->send_fn(req
);
830 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
831 struct ntvfs_request
*req
,
834 struct cvfs_private
*p
= ntvfs
->private_data
;
835 struct smbcli_request
*c_req
;
839 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
840 return smb_raw_seek(p
->tree
, io
);
843 c_req
= smb_raw_seek_send(p
->tree
, io
);
845 ASYNC_RECV_TAIL(io
, async_seek
);
851 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
852 struct ntvfs_request
*req
,
855 struct cvfs_private
*p
= ntvfs
->private_data
;
856 struct smbcli_request
*c_req
;
859 switch (io
->generic
.level
) {
860 case RAW_FLUSH_FLUSH
:
864 io
->generic
.in
.file
.fnum
= 0xFFFF;
867 return NT_STATUS_INVALID_LEVEL
;
870 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
871 return smb_raw_flush(p
->tree
, io
);
874 c_req
= smb_raw_flush_send(p
->tree
, io
);
882 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
883 struct ntvfs_request
*req
, union smb_close
*io
)
885 struct cvfs_private
*p
= ntvfs
->private_data
;
886 struct smbcli_request
*c_req
;
892 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
&&
894 return ntvfs_map_close(ntvfs
, req
, io
);
897 if (io
->generic
.level
== RAW_CLOSE_GENERIC
) {
899 io2
.close
.level
= RAW_CLOSE_CLOSE
;
900 io2
.close
.in
.file
= io
->generic
.in
.file
;
901 io2
.close
.in
.write_time
= io
->generic
.in
.write_time
;
906 /* Note, we aren't free-ing f, or it's h here. Should we?
907 even if file-close fails, we'll remove it from the list,
908 what else would we do? Maybe we should not remove until
909 after the proxied call completes? */
910 DLIST_REMOVE(p
->files
, f
);
912 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
913 return smb_raw_close(p
->tree
, io
);
916 c_req
= smb_raw_close_send(p
->tree
, io
);
922 exit - closing files open by the pid
924 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
925 struct ntvfs_request
*req
)
927 struct cvfs_private
*p
= ntvfs
->private_data
;
928 struct smbcli_request
*c_req
;
932 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
933 return smb_raw_exit(p
->tree
->session
);
936 c_req
= smb_raw_exit_send(p
->tree
->session
);
942 logoff - closing files open by the user
944 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
945 struct ntvfs_request
*req
)
947 /* we can't do this right in the cifs backend .... */
952 setup for an async call - nothing to do yet
954 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
955 struct ntvfs_request
*req
,
964 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
965 struct ntvfs_request
*req
)
967 struct cvfs_private
*p
= ntvfs
->private_data
;
968 struct async_info
*a
;
970 /* find the matching request */
971 for (a
=p
->pending
;a
;a
=a
->next
) {
978 return NT_STATUS_INVALID_PARAMETER
;
981 return smb_raw_ntcancel(a
->c_req
);
987 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
988 struct ntvfs_request
*req
, union smb_lock
*io
)
990 struct cvfs_private
*p
= ntvfs
->private_data
;
991 struct smbcli_request
*c_req
;
995 if (io
->generic
.level
!= RAW_LOCK_GENERIC
&&
997 return ntvfs_map_lock(ntvfs
, req
, io
);
1001 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1002 return smb_raw_lock(p
->tree
, io
);
1005 c_req
= smb_raw_lock_send(p
->tree
, io
);
1010 set info on a open file
1012 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
1013 struct ntvfs_request
*req
,
1014 union smb_setfileinfo
*io
)
1016 struct cvfs_private
*p
= ntvfs
->private_data
;
1017 struct smbcli_request
*c_req
;
1021 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1022 return smb_raw_setfileinfo(p
->tree
, io
);
1024 c_req
= smb_raw_setfileinfo_send(p
->tree
, io
);
1031 a handler for async fsinfo replies
1033 static void async_fsinfo(struct smbcli_request
*c_req
)
1035 struct async_info
*async
= c_req
->async
.private_data
;
1036 struct ntvfs_request
*req
= async
->req
;
1037 req
->async_states
->status
= smb_raw_fsinfo_recv(c_req
, req
, async
->parms
);
1039 req
->async_states
->send_fn(req
);
1043 return filesystem space info
1045 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
1046 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
1048 struct cvfs_private
*p
= ntvfs
->private_data
;
1049 struct smbcli_request
*c_req
;
1053 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1054 return smb_raw_fsinfo(p
->tree
, req
, fs
);
1057 c_req
= smb_raw_fsinfo_send(p
->tree
, req
, fs
);
1059 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
1063 return print queue info
1065 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
1066 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
1068 return NT_STATUS_NOT_SUPPORTED
;
1072 list files in a directory matching a wildcard pattern
1074 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
1075 struct ntvfs_request
*req
, union smb_search_first
*io
,
1076 void *search_private
,
1077 bool (*callback
)(void *, const union smb_search_data
*))
1079 struct cvfs_private
*p
= ntvfs
->private_data
;
1083 return smb_raw_search_first(p
->tree
, req
, io
, search_private
, callback
);
1086 /* continue a search */
1087 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
1088 struct ntvfs_request
*req
, union smb_search_next
*io
,
1089 void *search_private
,
1090 bool (*callback
)(void *, const union smb_search_data
*))
1092 struct cvfs_private
*p
= ntvfs
->private_data
;
1096 return smb_raw_search_next(p
->tree
, req
, io
, search_private
, callback
);
1099 /* close a search */
1100 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
1101 struct ntvfs_request
*req
, union smb_search_close
*io
)
1103 struct cvfs_private
*p
= ntvfs
->private_data
;
1107 return smb_raw_search_close(p
->tree
, io
);
1111 a handler for async trans2 replies
1113 static void async_trans2(struct smbcli_request
*c_req
)
1115 struct async_info
*async
= c_req
->async
.private_data
;
1116 struct ntvfs_request
*req
= async
->req
;
1117 req
->async_states
->status
= smb_raw_trans2_recv(c_req
, req
, async
->parms
);
1119 req
->async_states
->send_fn(req
);
1123 static NTSTATUS
cvfs_trans2(struct ntvfs_module_context
*ntvfs
,
1124 struct ntvfs_request
*req
,
1125 struct smb_trans2
*trans2
)
1127 struct cvfs_private
*p
= ntvfs
->private_data
;
1128 struct smbcli_request
*c_req
;
1130 if (p
->map_trans2
) {
1131 return NT_STATUS_NOT_IMPLEMENTED
;
1136 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1137 return smb_raw_trans2(p
->tree
, req
, trans2
);
1140 c_req
= smb_raw_trans2_send(p
->tree
, trans2
);
1142 ASYNC_RECV_TAIL(trans2
, async_trans2
);
1146 /* SMBtrans - not used on file shares */
1147 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
1148 struct ntvfs_request
*req
,
1149 struct smb_trans2
*trans2
)
1151 return NT_STATUS_ACCESS_DENIED
;
1155 a handler for async change notify replies
1157 static void async_changenotify(struct smbcli_request
*c_req
)
1159 struct async_info
*async
= c_req
->async
.private_data
;
1160 struct ntvfs_request
*req
= async
->req
;
1161 req
->async_states
->status
= smb_raw_changenotify_recv(c_req
, req
, async
->parms
);
1163 req
->async_states
->send_fn(req
);
1166 /* change notify request - always async */
1167 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
1168 struct ntvfs_request
*req
,
1169 union smb_notify
*io
)
1171 struct cvfs_private
*p
= ntvfs
->private_data
;
1172 struct smbcli_request
*c_req
;
1173 int saved_timeout
= p
->transport
->options
.request_timeout
;
1174 struct cvfs_file
*f
;
1176 if (io
->nttrans
.level
!= RAW_NOTIFY_NTTRANS
) {
1177 return NT_STATUS_NOT_IMPLEMENTED
;
1182 f
= ntvfs_handle_get_backend_data(io
->nttrans
.in
.file
.ntvfs
, ntvfs
);
1183 if (!f
) return NT_STATUS_INVALID_HANDLE
;
1184 io
->nttrans
.in
.file
.fnum
= f
->fnum
;
1186 /* this request doesn't make sense unless its async */
1187 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1188 return NT_STATUS_INVALID_PARAMETER
;
1191 /* we must not timeout on notify requests - they wait
1193 p
->transport
->options
.request_timeout
= 0;
1195 c_req
= smb_raw_changenotify_send(p
->tree
, io
);
1197 p
->transport
->options
.request_timeout
= saved_timeout
;
1199 ASYNC_RECV_TAIL(io
, async_changenotify
);
1203 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1205 NTSTATUS
ntvfs_cifs_init(TALLOC_CTX
*ctx
)
1208 struct ntvfs_ops ops
;
1209 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
1213 /* fill in the name and type */
1215 ops
.type
= NTVFS_DISK
;
1217 /* fill in all the operations */
1218 ops
.connect_fn
= cvfs_connect
;
1219 ops
.disconnect_fn
= cvfs_disconnect
;
1220 ops
.unlink_fn
= cvfs_unlink
;
1221 ops
.chkpath_fn
= cvfs_chkpath
;
1222 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
1223 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
1224 ops
.open_fn
= cvfs_open
;
1225 ops
.mkdir_fn
= cvfs_mkdir
;
1226 ops
.rmdir_fn
= cvfs_rmdir
;
1227 ops
.rename_fn
= cvfs_rename
;
1228 ops
.copy_fn
= cvfs_copy
;
1229 ops
.ioctl_fn
= cvfs_ioctl
;
1230 ops
.read_fn
= cvfs_read
;
1231 ops
.write_fn
= cvfs_write
;
1232 ops
.seek_fn
= cvfs_seek
;
1233 ops
.flush_fn
= cvfs_flush
;
1234 ops
.close_fn
= cvfs_close
;
1235 ops
.exit_fn
= cvfs_exit
;
1236 ops
.lock_fn
= cvfs_lock
;
1237 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
1238 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
1239 ops
.fsinfo_fn
= cvfs_fsinfo
;
1240 ops
.lpq_fn
= cvfs_lpq
;
1241 ops
.search_first_fn
= cvfs_search_first
;
1242 ops
.search_next_fn
= cvfs_search_next
;
1243 ops
.search_close_fn
= cvfs_search_close
;
1244 ops
.trans_fn
= cvfs_trans
;
1245 ops
.logoff_fn
= cvfs_logoff
;
1246 ops
.async_setup_fn
= cvfs_async_setup
;
1247 ops
.cancel_fn
= cvfs_cancel
;
1248 ops
.notify_fn
= cvfs_notify
;
1249 ops
.trans2_fn
= cvfs_trans2
;
1251 /* register ourselves with the NTVFS subsystem. We register
1252 under the name 'cifs'. */
1253 ret
= ntvfs_register(&ops
, &vers
);
1255 if (!NT_STATUS_IS_OK(ret
)) {
1256 DEBUG(0,("Failed to register CIFS backend!\n"));