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 return NT_STATUS_INVALID_LEVEL
;
179 if (strncmp(sharename
, "\\\\", 2) == 0) {
180 char *str
= strchr(sharename
+2, '\\');
186 /* Here we need to determine which server to connect to.
187 * For now we use parametric options, type cifs.
189 host
= share_string_option(tmp_ctx
, scfg
, CIFS_SERVER
, NULL
);
190 user
= share_string_option(tmp_ctx
, scfg
, CIFS_USER
, NULL
);
191 pass
= share_string_option(tmp_ctx
, scfg
, CIFS_PASSWORD
, NULL
);
192 domain
= share_string_option(tmp_ctx
, scfg
, CIFS_DOMAIN
, NULL
);
193 remote_share
= share_string_option(tmp_ctx
, scfg
, CIFS_SHARE
, NULL
);
195 remote_share
= sharename
;
198 machine_account
= share_bool_option(scfg
, CIFS_USE_MACHINE_ACCT
, CIFS_USE_MACHINE_ACCT_DEFAULT
);
199 s4u2proxy
= share_bool_option(scfg
, CIFS_USE_S4U2PROXY
, CIFS_USE_S4U2PROXY_DEFAULT
);
201 p
= talloc_zero(ntvfs
, struct cvfs_private
);
203 TALLOC_FREE(tmp_ctx
);
204 return NT_STATUS_NO_MEMORY
;
207 ntvfs
->private_data
= p
;
210 DEBUG(1,("CIFS backend: You must supply server\n"));
211 return NT_STATUS_INVALID_PARAMETER
;
215 DEBUG(5, ("CIFS backend: Using specified password\n"));
216 credentials
= cli_credentials_init(p
);
218 TALLOC_FREE(tmp_ctx
);
219 return NT_STATUS_NO_MEMORY
;
221 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
222 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
224 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
226 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
227 } else if (machine_account
) {
228 DEBUG(5, ("CIFS backend: Using machine account\n"));
229 credentials
= cli_credentials_init(p
);
230 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
232 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
234 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
235 if (!NT_STATUS_IS_OK(status
)) {
236 TALLOC_FREE(tmp_ctx
);
239 } else if (req
->session_info
->credentials
) {
240 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
241 credentials
= req
->session_info
->credentials
;
242 } else if (s4u2proxy
) {
243 struct ccache_container
*ccc
= NULL
;
244 const char *err_str
= NULL
;
246 char *impersonate_principal
;
248 char *target_service
;
250 impersonate_principal
= talloc_asprintf(req
, "%s@%s",
251 req
->session_info
->info
->account_name
,
252 req
->session_info
->info
->domain_name
);
254 self_service
= talloc_asprintf(req
, "cifs/%s",
255 lpcfg_netbios_name(ntvfs
->ctx
->lp_ctx
));
257 target_service
= talloc_asprintf(req
, "cifs/%s", host
);
259 DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
261 credentials
= cli_credentials_init(p
);
262 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
264 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
266 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
267 if (!NT_STATUS_IS_OK(status
)) {
268 TALLOC_FREE(tmp_ctx
);
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
)));
285 TALLOC_FREE(tmp_ctx
);
290 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
291 TALLOC_FREE(tmp_ctx
);
292 return NT_STATUS_INTERNAL_ERROR
;
295 /* connect to the server, using the smbd event context */
296 io
.in
.dest_host
= host
;
297 io
.in
.dest_ports
= lpcfg_smb_ports(ntvfs
->ctx
->lp_ctx
);
298 io
.in
.socket_options
= lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
);
299 io
.in
.called_name
= host
;
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
)) {
318 TALLOC_FREE(tmp_ctx
);
322 p
->tree
= io
.out
.tree
;
324 p
->transport
= p
->tree
->session
->transport
;
328 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
329 if (ntvfs
->ctx
->fs_type
== NULL
) {
330 TALLOC_FREE(tmp_ctx
);
331 return NT_STATUS_NO_MEMORY
;
333 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
334 if (ntvfs
->ctx
->dev_type
== NULL
) {
335 TALLOC_FREE(tmp_ctx
);
336 return NT_STATUS_NO_MEMORY
;
339 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
340 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
341 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
344 /* we need to receive oplock break requests from the server */
345 smbcli_oplock_handler(p
->transport
, oplock_handler
, p
);
347 p
->map_generic
= share_bool_option(scfg
, CIFS_MAP_GENERIC
, CIFS_MAP_GENERIC_DEFAULT
);
349 p
->map_trans2
= share_bool_option(scfg
, CIFS_MAP_TRANS2
, CIFS_MAP_TRANS2_DEFAULT
);
351 TALLOC_FREE(tmp_ctx
);
356 disconnect from a share
358 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
360 struct cvfs_private
*p
= ntvfs
->private_data
;
361 struct async_info
*a
, *an
;
363 /* first cleanup pending requests */
364 for (a
=p
->pending
; a
; a
= an
) {
366 smbcli_request_destroy(a
->c_req
);
371 ntvfs
->private_data
= NULL
;
377 destroy an async info structure
379 static int async_info_destructor(struct async_info
*async
)
381 DLIST_REMOVE(async
->cvfs
->pending
, async
);
386 a handler for simple async replies
387 this handler can only be used for functions that don't return any
388 parameters (those that just return a status code)
390 static void async_simple(struct smbcli_request
*c_req
)
392 struct async_info
*async
= c_req
->async
.private_data
;
393 struct ntvfs_request
*req
= async
->req
;
394 req
->async_states
->status
= smbcli_request_simple_recv(c_req
);
396 req
->async_states
->send_fn(req
);
400 /* save some typing for the simple functions */
401 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
402 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
404 struct async_info *async; \
405 async = talloc(req, struct async_info); \
406 if (!async) return NT_STATUS_NO_MEMORY; \
411 async->c_req = c_req; \
412 DLIST_ADD(p->pending, async); \
413 c_req->async.private_data = async; \
414 talloc_set_destructor(async, async_info_destructor); \
416 c_req->async.fn = async_fn; \
417 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
418 return NT_STATUS_OK; \
421 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
423 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
426 delete a file - the dirtype specifies the file types to include in the search.
427 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
429 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
430 struct ntvfs_request
*req
, union smb_unlink
*unl
)
432 struct cvfs_private
*p
= ntvfs
->private_data
;
433 struct smbcli_request
*c_req
;
437 /* see if the front end will allow us to perform this
438 function asynchronously. */
439 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
440 return smb_raw_unlink(p
->tree
, unl
);
443 c_req
= smb_raw_unlink_send(p
->tree
, unl
);
449 a handler for async ioctl replies
451 static void async_ioctl(struct smbcli_request
*c_req
)
453 struct async_info
*async
= c_req
->async
.private_data
;
454 struct ntvfs_request
*req
= async
->req
;
455 req
->async_states
->status
= smb_raw_ioctl_recv(c_req
, req
, async
->parms
);
457 req
->async_states
->send_fn(req
);
463 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
464 struct ntvfs_request
*req
, union smb_ioctl
*io
)
466 struct cvfs_private
*p
= ntvfs
->private_data
;
467 struct smbcli_request
*c_req
;
471 /* see if the front end will allow us to perform this
472 function asynchronously. */
473 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
474 return smb_raw_ioctl(p
->tree
, req
, io
);
477 c_req
= smb_raw_ioctl_send(p
->tree
, io
);
479 ASYNC_RECV_TAIL(io
, async_ioctl
);
483 check if a directory exists
485 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
486 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
488 struct cvfs_private
*p
= ntvfs
->private_data
;
489 struct smbcli_request
*c_req
;
493 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
494 return smb_raw_chkpath(p
->tree
, cp
);
497 c_req
= smb_raw_chkpath_send(p
->tree
, cp
);
503 a handler for async qpathinfo replies
505 static void async_qpathinfo(struct smbcli_request
*c_req
)
507 struct async_info
*async
= c_req
->async
.private_data
;
508 struct ntvfs_request
*req
= async
->req
;
509 req
->async_states
->status
= smb_raw_pathinfo_recv(c_req
, req
, async
->parms
);
511 req
->async_states
->send_fn(req
);
515 return info on a pathname
517 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
518 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
520 struct cvfs_private
*p
= ntvfs
->private_data
;
521 struct smbcli_request
*c_req
;
525 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
526 return smb_raw_pathinfo(p
->tree
, req
, info
);
529 c_req
= smb_raw_pathinfo_send(p
->tree
, info
);
531 ASYNC_RECV_TAIL(info
, async_qpathinfo
);
535 a handler for async qfileinfo replies
537 static void async_qfileinfo(struct smbcli_request
*c_req
)
539 struct async_info
*async
= c_req
->async
.private_data
;
540 struct ntvfs_request
*req
= async
->req
;
541 req
->async_states
->status
= smb_raw_fileinfo_recv(c_req
, req
, async
->parms
);
543 req
->async_states
->send_fn(req
);
547 query info on a open file
549 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
550 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
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_fileinfo(p
->tree
, req
, io
);
561 c_req
= smb_raw_fileinfo_send(p
->tree
, io
);
563 ASYNC_RECV_TAIL(io
, async_qfileinfo
);
568 set info on a pathname
570 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
571 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
573 struct cvfs_private
*p
= ntvfs
->private_data
;
574 struct smbcli_request
*c_req
;
578 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
579 return smb_raw_setpathinfo(p
->tree
, st
);
582 c_req
= smb_raw_setpathinfo_send(p
->tree
, st
);
589 a handler for async open replies
591 static void async_open(struct smbcli_request
*c_req
)
593 struct async_info
*async
= c_req
->async
.private_data
;
594 struct cvfs_private
*cvfs
= async
->cvfs
;
595 struct ntvfs_request
*req
= async
->req
;
596 struct cvfs_file
*f
= async
->f
;
597 union smb_open
*io
= async
->parms
;
598 union smb_handle
*file
;
600 req
->async_states
->status
= smb_raw_open_recv(c_req
, req
, io
);
601 SMB_OPEN_OUT_FILE(io
, file
);
602 f
->fnum
= file
->fnum
;
604 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
605 req
->async_states
->status
= ntvfs_handle_set_backend_data(f
->h
, cvfs
->ntvfs
, f
);
606 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
608 DLIST_ADD(cvfs
->files
, f
);
610 req
->async_states
->send_fn(req
);
616 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
617 struct ntvfs_request
*req
, union smb_open
*io
)
619 struct cvfs_private
*p
= ntvfs
->private_data
;
620 struct smbcli_request
*c_req
;
621 struct ntvfs_handle
*h
;
627 if (io
->generic
.level
!= RAW_OPEN_GENERIC
&&
629 return ntvfs_map_open(ntvfs
, req
, io
);
632 status
= ntvfs_handle_new(ntvfs
, req
, &h
);
633 NT_STATUS_NOT_OK_RETURN(status
);
635 f
= talloc_zero(h
, struct cvfs_file
);
636 NT_STATUS_HAVE_NO_MEMORY(f
);
639 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
640 union smb_handle
*file
;
642 status
= smb_raw_open(p
->tree
, req
, io
);
643 NT_STATUS_NOT_OK_RETURN(status
);
645 SMB_OPEN_OUT_FILE(io
, file
);
646 f
->fnum
= file
->fnum
;
648 status
= ntvfs_handle_set_backend_data(f
->h
, p
->ntvfs
, f
);
649 NT_STATUS_NOT_OK_RETURN(status
);
651 DLIST_ADD(p
->files
, f
);
656 c_req
= smb_raw_open_send(p
->tree
, io
);
658 ASYNC_RECV_TAIL_F(io
, async_open
, f
);
664 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
665 struct ntvfs_request
*req
, union smb_mkdir
*md
)
667 struct cvfs_private
*p
= ntvfs
->private_data
;
668 struct smbcli_request
*c_req
;
672 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
673 return smb_raw_mkdir(p
->tree
, md
);
676 c_req
= smb_raw_mkdir_send(p
->tree
, md
);
684 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
685 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
687 struct cvfs_private
*p
= ntvfs
->private_data
;
688 struct smbcli_request
*c_req
;
692 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
693 return smb_raw_rmdir(p
->tree
, rd
);
695 c_req
= smb_raw_rmdir_send(p
->tree
, rd
);
701 rename a set of files
703 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
704 struct ntvfs_request
*req
, union smb_rename
*ren
)
706 struct cvfs_private
*p
= ntvfs
->private_data
;
707 struct smbcli_request
*c_req
;
711 if (ren
->nttrans
.level
== RAW_RENAME_NTTRANS
) {
713 f
= ntvfs_handle_get_backend_data(ren
->nttrans
.in
.file
.ntvfs
, ntvfs
);
714 if (!f
) return NT_STATUS_INVALID_HANDLE
;
715 ren
->nttrans
.in
.file
.fnum
= f
->fnum
;
718 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
719 return smb_raw_rename(p
->tree
, ren
);
722 c_req
= smb_raw_rename_send(p
->tree
, ren
);
730 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
731 struct ntvfs_request
*req
, struct smb_copy
*cp
)
733 return NT_STATUS_NOT_SUPPORTED
;
737 a handler for async read replies
739 static void async_read(struct smbcli_request
*c_req
)
741 struct async_info
*async
= c_req
->async
.private_data
;
742 struct ntvfs_request
*req
= async
->req
;
743 req
->async_states
->status
= smb_raw_read_recv(c_req
, async
->parms
);
745 req
->async_states
->send_fn(req
);
751 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
752 struct ntvfs_request
*req
, union smb_read
*io
)
754 struct cvfs_private
*p
= ntvfs
->private_data
;
755 struct smbcli_request
*c_req
;
759 if (io
->generic
.level
!= RAW_READ_GENERIC
&&
761 return ntvfs_map_read(ntvfs
, req
, io
);
766 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
767 return smb_raw_read(p
->tree
, io
);
770 c_req
= smb_raw_read_send(p
->tree
, io
);
772 ASYNC_RECV_TAIL(io
, async_read
);
776 a handler for async write replies
778 static void async_write(struct smbcli_request
*c_req
)
780 struct async_info
*async
= c_req
->async
.private_data
;
781 struct ntvfs_request
*req
= async
->req
;
782 req
->async_states
->status
= smb_raw_write_recv(c_req
, async
->parms
);
784 req
->async_states
->send_fn(req
);
790 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
791 struct ntvfs_request
*req
, union smb_write
*io
)
793 struct cvfs_private
*p
= ntvfs
->private_data
;
794 struct smbcli_request
*c_req
;
798 if (io
->generic
.level
!= RAW_WRITE_GENERIC
&&
800 return ntvfs_map_write(ntvfs
, req
, io
);
804 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
805 return smb_raw_write(p
->tree
, io
);
808 c_req
= smb_raw_write_send(p
->tree
, io
);
810 ASYNC_RECV_TAIL(io
, async_write
);
814 a handler for async seek replies
816 static void async_seek(struct smbcli_request
*c_req
)
818 struct async_info
*async
= c_req
->async
.private_data
;
819 struct ntvfs_request
*req
= async
->req
;
820 req
->async_states
->status
= smb_raw_seek_recv(c_req
, async
->parms
);
822 req
->async_states
->send_fn(req
);
828 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
829 struct ntvfs_request
*req
,
832 struct cvfs_private
*p
= ntvfs
->private_data
;
833 struct smbcli_request
*c_req
;
837 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
838 return smb_raw_seek(p
->tree
, io
);
841 c_req
= smb_raw_seek_send(p
->tree
, io
);
843 ASYNC_RECV_TAIL(io
, async_seek
);
849 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
850 struct ntvfs_request
*req
,
853 struct cvfs_private
*p
= ntvfs
->private_data
;
854 struct smbcli_request
*c_req
;
857 switch (io
->generic
.level
) {
858 case RAW_FLUSH_FLUSH
:
862 io
->generic
.in
.file
.fnum
= 0xFFFF;
865 return NT_STATUS_INVALID_LEVEL
;
868 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
869 return smb_raw_flush(p
->tree
, io
);
872 c_req
= smb_raw_flush_send(p
->tree
, io
);
880 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
881 struct ntvfs_request
*req
, union smb_close
*io
)
883 struct cvfs_private
*p
= ntvfs
->private_data
;
884 struct smbcli_request
*c_req
;
890 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
&&
892 return ntvfs_map_close(ntvfs
, req
, io
);
895 if (io
->generic
.level
== RAW_CLOSE_GENERIC
) {
897 io2
.close
.level
= RAW_CLOSE_CLOSE
;
898 io2
.close
.in
.file
= io
->generic
.in
.file
;
899 io2
.close
.in
.write_time
= io
->generic
.in
.write_time
;
904 /* Note, we aren't free-ing f, or it's h here. Should we?
905 even if file-close fails, we'll remove it from the list,
906 what else would we do? Maybe we should not remove until
907 after the proxied call completes? */
908 DLIST_REMOVE(p
->files
, f
);
910 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
911 return smb_raw_close(p
->tree
, io
);
914 c_req
= smb_raw_close_send(p
->tree
, io
);
920 exit - closing files open by the pid
922 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
923 struct ntvfs_request
*req
)
925 struct cvfs_private
*p
= ntvfs
->private_data
;
926 struct smbcli_request
*c_req
;
930 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
931 return smb_raw_exit(p
->tree
->session
);
934 c_req
= smb_raw_exit_send(p
->tree
->session
);
940 logoff - closing files open by the user
942 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
943 struct ntvfs_request
*req
)
945 /* we can't do this right in the cifs backend .... */
950 setup for an async call - nothing to do yet
952 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
953 struct ntvfs_request
*req
,
962 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
963 struct ntvfs_request
*req
)
965 struct cvfs_private
*p
= ntvfs
->private_data
;
966 struct async_info
*a
;
968 /* find the matching request */
969 for (a
=p
->pending
;a
;a
=a
->next
) {
976 return NT_STATUS_INVALID_PARAMETER
;
979 return smb_raw_ntcancel(a
->c_req
);
985 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
986 struct ntvfs_request
*req
, union smb_lock
*io
)
988 struct cvfs_private
*p
= ntvfs
->private_data
;
989 struct smbcli_request
*c_req
;
993 if (io
->generic
.level
!= RAW_LOCK_GENERIC
&&
995 return ntvfs_map_lock(ntvfs
, req
, io
);
999 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1000 return smb_raw_lock(p
->tree
, io
);
1003 c_req
= smb_raw_lock_send(p
->tree
, io
);
1008 set info on a open file
1010 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
1011 struct ntvfs_request
*req
,
1012 union smb_setfileinfo
*io
)
1014 struct cvfs_private
*p
= ntvfs
->private_data
;
1015 struct smbcli_request
*c_req
;
1019 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1020 return smb_raw_setfileinfo(p
->tree
, io
);
1022 c_req
= smb_raw_setfileinfo_send(p
->tree
, io
);
1029 a handler for async fsinfo replies
1031 static void async_fsinfo(struct smbcli_request
*c_req
)
1033 struct async_info
*async
= c_req
->async
.private_data
;
1034 struct ntvfs_request
*req
= async
->req
;
1035 req
->async_states
->status
= smb_raw_fsinfo_recv(c_req
, req
, async
->parms
);
1037 req
->async_states
->send_fn(req
);
1041 return filesystem space info
1043 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
1044 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
1046 struct cvfs_private
*p
= ntvfs
->private_data
;
1047 struct smbcli_request
*c_req
;
1051 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1052 return smb_raw_fsinfo(p
->tree
, req
, fs
);
1055 c_req
= smb_raw_fsinfo_send(p
->tree
, req
, fs
);
1057 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
1061 return print queue info
1063 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
1064 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
1066 return NT_STATUS_NOT_SUPPORTED
;
1070 list files in a directory matching a wildcard pattern
1072 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
1073 struct ntvfs_request
*req
, union smb_search_first
*io
,
1074 void *search_private
,
1075 bool (*callback
)(void *, const union smb_search_data
*))
1077 struct cvfs_private
*p
= ntvfs
->private_data
;
1081 return smb_raw_search_first(p
->tree
, req
, io
, search_private
, callback
);
1084 /* continue a search */
1085 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
1086 struct ntvfs_request
*req
, union smb_search_next
*io
,
1087 void *search_private
,
1088 bool (*callback
)(void *, const union smb_search_data
*))
1090 struct cvfs_private
*p
= ntvfs
->private_data
;
1094 return smb_raw_search_next(p
->tree
, req
, io
, search_private
, callback
);
1097 /* close a search */
1098 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
1099 struct ntvfs_request
*req
, union smb_search_close
*io
)
1101 struct cvfs_private
*p
= ntvfs
->private_data
;
1105 return smb_raw_search_close(p
->tree
, io
);
1109 a handler for async trans2 replies
1111 static void async_trans2(struct smbcli_request
*c_req
)
1113 struct async_info
*async
= c_req
->async
.private_data
;
1114 struct ntvfs_request
*req
= async
->req
;
1115 req
->async_states
->status
= smb_raw_trans2_recv(c_req
, req
, async
->parms
);
1117 req
->async_states
->send_fn(req
);
1121 static NTSTATUS
cvfs_trans2(struct ntvfs_module_context
*ntvfs
,
1122 struct ntvfs_request
*req
,
1123 struct smb_trans2
*trans2
)
1125 struct cvfs_private
*p
= ntvfs
->private_data
;
1126 struct smbcli_request
*c_req
;
1128 if (p
->map_trans2
) {
1129 return NT_STATUS_NOT_IMPLEMENTED
;
1134 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1135 return smb_raw_trans2(p
->tree
, req
, trans2
);
1138 c_req
= smb_raw_trans2_send(p
->tree
, trans2
);
1140 ASYNC_RECV_TAIL(trans2
, async_trans2
);
1144 /* SMBtrans - not used on file shares */
1145 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
1146 struct ntvfs_request
*req
,
1147 struct smb_trans2
*trans2
)
1149 return NT_STATUS_ACCESS_DENIED
;
1153 a handler for async change notify replies
1155 static void async_changenotify(struct smbcli_request
*c_req
)
1157 struct async_info
*async
= c_req
->async
.private_data
;
1158 struct ntvfs_request
*req
= async
->req
;
1159 req
->async_states
->status
= smb_raw_changenotify_recv(c_req
, req
, async
->parms
);
1161 req
->async_states
->send_fn(req
);
1164 /* change notify request - always async */
1165 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
1166 struct ntvfs_request
*req
,
1167 union smb_notify
*io
)
1169 struct cvfs_private
*p
= ntvfs
->private_data
;
1170 struct smbcli_request
*c_req
;
1171 int saved_timeout
= p
->transport
->options
.request_timeout
;
1172 struct cvfs_file
*f
;
1174 if (io
->nttrans
.level
!= RAW_NOTIFY_NTTRANS
) {
1175 return NT_STATUS_NOT_IMPLEMENTED
;
1180 f
= ntvfs_handle_get_backend_data(io
->nttrans
.in
.file
.ntvfs
, ntvfs
);
1181 if (!f
) return NT_STATUS_INVALID_HANDLE
;
1182 io
->nttrans
.in
.file
.fnum
= f
->fnum
;
1184 /* this request doesn't make sense unless its async */
1185 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1186 return NT_STATUS_INVALID_PARAMETER
;
1189 /* we must not timeout on notify requests - they wait
1191 p
->transport
->options
.request_timeout
= 0;
1193 c_req
= smb_raw_changenotify_send(p
->tree
, io
);
1195 p
->transport
->options
.request_timeout
= saved_timeout
;
1197 ASYNC_RECV_TAIL(io
, async_changenotify
);
1201 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1203 NTSTATUS
ntvfs_cifs_init(void)
1206 struct ntvfs_ops ops
;
1207 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
1211 /* fill in the name and type */
1213 ops
.type
= NTVFS_DISK
;
1215 /* fill in all the operations */
1216 ops
.connect_fn
= cvfs_connect
;
1217 ops
.disconnect_fn
= cvfs_disconnect
;
1218 ops
.unlink_fn
= cvfs_unlink
;
1219 ops
.chkpath_fn
= cvfs_chkpath
;
1220 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
1221 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
1222 ops
.open_fn
= cvfs_open
;
1223 ops
.mkdir_fn
= cvfs_mkdir
;
1224 ops
.rmdir_fn
= cvfs_rmdir
;
1225 ops
.rename_fn
= cvfs_rename
;
1226 ops
.copy_fn
= cvfs_copy
;
1227 ops
.ioctl_fn
= cvfs_ioctl
;
1228 ops
.read_fn
= cvfs_read
;
1229 ops
.write_fn
= cvfs_write
;
1230 ops
.seek_fn
= cvfs_seek
;
1231 ops
.flush_fn
= cvfs_flush
;
1232 ops
.close_fn
= cvfs_close
;
1233 ops
.exit_fn
= cvfs_exit
;
1234 ops
.lock_fn
= cvfs_lock
;
1235 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
1236 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
1237 ops
.fsinfo_fn
= cvfs_fsinfo
;
1238 ops
.lpq_fn
= cvfs_lpq
;
1239 ops
.search_first_fn
= cvfs_search_first
;
1240 ops
.search_next_fn
= cvfs_search_next
;
1241 ops
.search_close_fn
= cvfs_search_close
;
1242 ops
.trans_fn
= cvfs_trans
;
1243 ops
.logoff_fn
= cvfs_logoff
;
1244 ops
.async_setup_fn
= cvfs_async_setup
;
1245 ops
.cancel_fn
= cvfs_cancel
;
1246 ops
.notify_fn
= cvfs_notify
;
1247 ops
.trans2_fn
= cvfs_trans2
;
1249 /* register ourselves with the NTVFS subsystem. We register
1250 under the name 'cifs'. */
1251 ret
= ntvfs_register(&ops
, &vers
);
1253 if (!NT_STATUS_IS_OK(ret
)) {
1254 DEBUG(0,("Failed to register CIFS backend!\n"));