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.
183 host
= share_string_option(scfg
, CIFS_SERVER
, NULL
);
184 user
= share_string_option(scfg
, CIFS_USER
, NULL
);
185 pass
= share_string_option(scfg
, CIFS_PASSWORD
, NULL
);
186 domain
= share_string_option(scfg
, CIFS_DOMAIN
, NULL
);
187 remote_share
= share_string_option(scfg
, CIFS_SHARE
, NULL
);
189 remote_share
= sharename
;
192 machine_account
= share_bool_option(scfg
, CIFS_USE_MACHINE_ACCT
, CIFS_USE_MACHINE_ACCT_DEFAULT
);
193 s4u2proxy
= share_bool_option(scfg
, CIFS_USE_S4U2PROXY
, CIFS_USE_S4U2PROXY_DEFAULT
);
195 p
= talloc_zero(ntvfs
, struct cvfs_private
);
197 return NT_STATUS_NO_MEMORY
;
200 ntvfs
->private_data
= p
;
203 DEBUG(1,("CIFS backend: You must supply server\n"));
204 return NT_STATUS_INVALID_PARAMETER
;
208 DEBUG(5, ("CIFS backend: Using specified password\n"));
209 credentials
= cli_credentials_init(p
);
211 return NT_STATUS_NO_MEMORY
;
213 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
214 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
216 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
218 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
219 } else if (machine_account
) {
220 DEBUG(5, ("CIFS backend: Using machine account\n"));
221 credentials
= cli_credentials_init(p
);
222 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
224 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
226 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
227 if (!NT_STATUS_IS_OK(status
)) {
230 } else if (req
->session_info
->credentials
) {
231 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
232 credentials
= req
->session_info
->credentials
;
233 } else if (s4u2proxy
) {
234 struct ccache_container
*ccc
= NULL
;
235 const char *err_str
= NULL
;
237 char *impersonate_principal
;
239 char *target_service
;
241 impersonate_principal
= talloc_asprintf(req
, "%s@%s",
242 req
->session_info
->info
->account_name
,
243 req
->session_info
->info
->domain_name
);
245 self_service
= talloc_asprintf(req
, "cifs/%s",
246 lpcfg_netbios_name(ntvfs
->ctx
->lp_ctx
));
248 target_service
= talloc_asprintf(req
, "cifs/%s", host
);
250 DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
252 credentials
= cli_credentials_init(p
);
253 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
255 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
257 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
258 if (!NT_STATUS_IS_OK(status
)) {
261 cli_credentials_invalidate_ccache(credentials
, CRED_SPECIFIED
);
262 cli_credentials_set_impersonate_principal(credentials
,
263 impersonate_principal
,
265 cli_credentials_set_target_service(credentials
, target_service
);
266 ret
= cli_credentials_get_ccache(credentials
,
267 ntvfs
->ctx
->event_ctx
,
272 status
= NT_STATUS_CROSSREALM_DELEGATION_FAILURE
;
273 DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n",
274 ret
, err_str
, nt_errstr(status
)));
279 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
280 return NT_STATUS_INTERNAL_ERROR
;
283 /* connect to the server, using the smbd event context */
284 io
.in
.dest_host
= host
;
285 io
.in
.dest_ports
= lpcfg_smb_ports(ntvfs
->ctx
->lp_ctx
);
286 io
.in
.socket_options
= lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
);
287 io
.in
.called_name
= host
;
288 io
.in
.credentials
= credentials
;
289 io
.in
.fallback_to_anonymous
= false;
290 io
.in
.workgroup
= lpcfg_workgroup(ntvfs
->ctx
->lp_ctx
);
291 io
.in
.service
= remote_share
;
292 io
.in
.service_type
= "?????";
293 io
.in
.gensec_settings
= lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
);
294 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.options
);
295 lpcfg_smbcli_session_options(ntvfs
->ctx
->lp_ctx
, &io
.in
.session_options
);
297 if (!(ntvfs
->ctx
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
)) {
298 io
.in
.options
.use_level2_oplocks
= false;
301 creq
= smb_composite_connect_send(&io
, p
,
302 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
303 ntvfs
->ctx
->event_ctx
);
304 status
= smb_composite_connect_recv(creq
, p
);
305 NT_STATUS_NOT_OK_RETURN(status
);
307 p
->tree
= io
.out
.tree
;
309 p
->transport
= p
->tree
->session
->transport
;
313 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
314 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
315 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
316 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
318 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
319 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
320 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
323 /* we need to receive oplock break requests from the server */
324 smbcli_oplock_handler(p
->transport
, oplock_handler
, p
);
326 p
->map_generic
= share_bool_option(scfg
, CIFS_MAP_GENERIC
, CIFS_MAP_GENERIC_DEFAULT
);
328 p
->map_trans2
= share_bool_option(scfg
, CIFS_MAP_TRANS2
, CIFS_MAP_TRANS2_DEFAULT
);
334 disconnect from a share
336 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
338 struct cvfs_private
*p
= ntvfs
->private_data
;
339 struct async_info
*a
, *an
;
341 /* first cleanup pending requests */
342 for (a
=p
->pending
; a
; a
= an
) {
344 smbcli_request_destroy(a
->c_req
);
349 ntvfs
->private_data
= NULL
;
355 destroy an async info structure
357 static int async_info_destructor(struct async_info
*async
)
359 DLIST_REMOVE(async
->cvfs
->pending
, async
);
364 a handler for simple async replies
365 this handler can only be used for functions that don't return any
366 parameters (those that just return a status code)
368 static void async_simple(struct smbcli_request
*c_req
)
370 struct async_info
*async
= c_req
->async
.private_data
;
371 struct ntvfs_request
*req
= async
->req
;
372 req
->async_states
->status
= smbcli_request_simple_recv(c_req
);
374 req
->async_states
->send_fn(req
);
378 /* save some typing for the simple functions */
379 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
380 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
382 struct async_info *async; \
383 async = talloc(req, struct async_info); \
384 if (!async) return NT_STATUS_NO_MEMORY; \
389 async->c_req = c_req; \
390 DLIST_ADD(p->pending, async); \
391 c_req->async.private_data = async; \
392 talloc_set_destructor(async, async_info_destructor); \
394 c_req->async.fn = async_fn; \
395 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
396 return NT_STATUS_OK; \
399 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
401 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
404 delete a file - the dirtype specifies the file types to include in the search.
405 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
407 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
408 struct ntvfs_request
*req
, union smb_unlink
*unl
)
410 struct cvfs_private
*p
= ntvfs
->private_data
;
411 struct smbcli_request
*c_req
;
415 /* see if the front end will allow us to perform this
416 function asynchronously. */
417 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
418 return smb_raw_unlink(p
->tree
, unl
);
421 c_req
= smb_raw_unlink_send(p
->tree
, unl
);
427 a handler for async ioctl replies
429 static void async_ioctl(struct smbcli_request
*c_req
)
431 struct async_info
*async
= c_req
->async
.private_data
;
432 struct ntvfs_request
*req
= async
->req
;
433 req
->async_states
->status
= smb_raw_ioctl_recv(c_req
, req
, async
->parms
);
435 req
->async_states
->send_fn(req
);
441 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
442 struct ntvfs_request
*req
, union smb_ioctl
*io
)
444 struct cvfs_private
*p
= ntvfs
->private_data
;
445 struct smbcli_request
*c_req
;
449 /* see if the front end will allow us to perform this
450 function asynchronously. */
451 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
452 return smb_raw_ioctl(p
->tree
, req
, io
);
455 c_req
= smb_raw_ioctl_send(p
->tree
, io
);
457 ASYNC_RECV_TAIL(io
, async_ioctl
);
461 check if a directory exists
463 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
464 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
466 struct cvfs_private
*p
= ntvfs
->private_data
;
467 struct smbcli_request
*c_req
;
471 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
472 return smb_raw_chkpath(p
->tree
, cp
);
475 c_req
= smb_raw_chkpath_send(p
->tree
, cp
);
481 a handler for async qpathinfo replies
483 static void async_qpathinfo(struct smbcli_request
*c_req
)
485 struct async_info
*async
= c_req
->async
.private_data
;
486 struct ntvfs_request
*req
= async
->req
;
487 req
->async_states
->status
= smb_raw_pathinfo_recv(c_req
, req
, async
->parms
);
489 req
->async_states
->send_fn(req
);
493 return info on a pathname
495 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
496 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
498 struct cvfs_private
*p
= ntvfs
->private_data
;
499 struct smbcli_request
*c_req
;
503 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
504 return smb_raw_pathinfo(p
->tree
, req
, info
);
507 c_req
= smb_raw_pathinfo_send(p
->tree
, info
);
509 ASYNC_RECV_TAIL(info
, async_qpathinfo
);
513 a handler for async qfileinfo replies
515 static void async_qfileinfo(struct smbcli_request
*c_req
)
517 struct async_info
*async
= c_req
->async
.private_data
;
518 struct ntvfs_request
*req
= async
->req
;
519 req
->async_states
->status
= smb_raw_fileinfo_recv(c_req
, req
, async
->parms
);
521 req
->async_states
->send_fn(req
);
525 query info on a open file
527 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
528 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
530 struct cvfs_private
*p
= ntvfs
->private_data
;
531 struct smbcli_request
*c_req
;
535 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
536 return smb_raw_fileinfo(p
->tree
, req
, io
);
539 c_req
= smb_raw_fileinfo_send(p
->tree
, io
);
541 ASYNC_RECV_TAIL(io
, async_qfileinfo
);
546 set info on a pathname
548 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
549 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
551 struct cvfs_private
*p
= ntvfs
->private_data
;
552 struct smbcli_request
*c_req
;
556 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
557 return smb_raw_setpathinfo(p
->tree
, st
);
560 c_req
= smb_raw_setpathinfo_send(p
->tree
, st
);
567 a handler for async open replies
569 static void async_open(struct smbcli_request
*c_req
)
571 struct async_info
*async
= c_req
->async
.private_data
;
572 struct cvfs_private
*cvfs
= async
->cvfs
;
573 struct ntvfs_request
*req
= async
->req
;
574 struct cvfs_file
*f
= async
->f
;
575 union smb_open
*io
= async
->parms
;
576 union smb_handle
*file
;
578 req
->async_states
->status
= smb_raw_open_recv(c_req
, req
, io
);
579 SMB_OPEN_OUT_FILE(io
, file
);
580 f
->fnum
= file
->fnum
;
582 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
583 req
->async_states
->status
= ntvfs_handle_set_backend_data(f
->h
, cvfs
->ntvfs
, f
);
584 if (!NT_STATUS_IS_OK(req
->async_states
->status
)) goto failed
;
586 DLIST_ADD(cvfs
->files
, f
);
588 req
->async_states
->send_fn(req
);
594 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
595 struct ntvfs_request
*req
, union smb_open
*io
)
597 struct cvfs_private
*p
= ntvfs
->private_data
;
598 struct smbcli_request
*c_req
;
599 struct ntvfs_handle
*h
;
605 if (io
->generic
.level
!= RAW_OPEN_GENERIC
&&
607 return ntvfs_map_open(ntvfs
, req
, io
);
610 status
= ntvfs_handle_new(ntvfs
, req
, &h
);
611 NT_STATUS_NOT_OK_RETURN(status
);
613 f
= talloc_zero(h
, struct cvfs_file
);
614 NT_STATUS_HAVE_NO_MEMORY(f
);
617 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
618 union smb_handle
*file
;
620 status
= smb_raw_open(p
->tree
, req
, io
);
621 NT_STATUS_NOT_OK_RETURN(status
);
623 SMB_OPEN_OUT_FILE(io
, file
);
624 f
->fnum
= file
->fnum
;
626 status
= ntvfs_handle_set_backend_data(f
->h
, p
->ntvfs
, f
);
627 NT_STATUS_NOT_OK_RETURN(status
);
629 DLIST_ADD(p
->files
, f
);
634 c_req
= smb_raw_open_send(p
->tree
, io
);
636 ASYNC_RECV_TAIL_F(io
, async_open
, f
);
642 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
643 struct ntvfs_request
*req
, union smb_mkdir
*md
)
645 struct cvfs_private
*p
= ntvfs
->private_data
;
646 struct smbcli_request
*c_req
;
650 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
651 return smb_raw_mkdir(p
->tree
, md
);
654 c_req
= smb_raw_mkdir_send(p
->tree
, md
);
662 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
663 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
665 struct cvfs_private
*p
= ntvfs
->private_data
;
666 struct smbcli_request
*c_req
;
670 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
671 return smb_raw_rmdir(p
->tree
, rd
);
673 c_req
= smb_raw_rmdir_send(p
->tree
, rd
);
679 rename a set of files
681 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
682 struct ntvfs_request
*req
, union smb_rename
*ren
)
684 struct cvfs_private
*p
= ntvfs
->private_data
;
685 struct smbcli_request
*c_req
;
689 if (ren
->nttrans
.level
== RAW_RENAME_NTTRANS
) {
691 f
= ntvfs_handle_get_backend_data(ren
->nttrans
.in
.file
.ntvfs
, ntvfs
);
692 if (!f
) return NT_STATUS_INVALID_HANDLE
;
693 ren
->nttrans
.in
.file
.fnum
= f
->fnum
;
696 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
697 return smb_raw_rename(p
->tree
, ren
);
700 c_req
= smb_raw_rename_send(p
->tree
, ren
);
708 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
709 struct ntvfs_request
*req
, struct smb_copy
*cp
)
711 return NT_STATUS_NOT_SUPPORTED
;
715 a handler for async read replies
717 static void async_read(struct smbcli_request
*c_req
)
719 struct async_info
*async
= c_req
->async
.private_data
;
720 struct ntvfs_request
*req
= async
->req
;
721 req
->async_states
->status
= smb_raw_read_recv(c_req
, async
->parms
);
723 req
->async_states
->send_fn(req
);
729 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
730 struct ntvfs_request
*req
, union smb_read
*io
)
732 struct cvfs_private
*p
= ntvfs
->private_data
;
733 struct smbcli_request
*c_req
;
737 if (io
->generic
.level
!= RAW_READ_GENERIC
&&
739 return ntvfs_map_read(ntvfs
, req
, io
);
744 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
745 return smb_raw_read(p
->tree
, io
);
748 c_req
= smb_raw_read_send(p
->tree
, io
);
750 ASYNC_RECV_TAIL(io
, async_read
);
754 a handler for async write replies
756 static void async_write(struct smbcli_request
*c_req
)
758 struct async_info
*async
= c_req
->async
.private_data
;
759 struct ntvfs_request
*req
= async
->req
;
760 req
->async_states
->status
= smb_raw_write_recv(c_req
, async
->parms
);
762 req
->async_states
->send_fn(req
);
768 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
769 struct ntvfs_request
*req
, union smb_write
*io
)
771 struct cvfs_private
*p
= ntvfs
->private_data
;
772 struct smbcli_request
*c_req
;
776 if (io
->generic
.level
!= RAW_WRITE_GENERIC
&&
778 return ntvfs_map_write(ntvfs
, req
, io
);
782 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
783 return smb_raw_write(p
->tree
, io
);
786 c_req
= smb_raw_write_send(p
->tree
, io
);
788 ASYNC_RECV_TAIL(io
, async_write
);
792 a handler for async seek replies
794 static void async_seek(struct smbcli_request
*c_req
)
796 struct async_info
*async
= c_req
->async
.private_data
;
797 struct ntvfs_request
*req
= async
->req
;
798 req
->async_states
->status
= smb_raw_seek_recv(c_req
, async
->parms
);
800 req
->async_states
->send_fn(req
);
806 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
807 struct ntvfs_request
*req
,
810 struct cvfs_private
*p
= ntvfs
->private_data
;
811 struct smbcli_request
*c_req
;
815 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
816 return smb_raw_seek(p
->tree
, io
);
819 c_req
= smb_raw_seek_send(p
->tree
, io
);
821 ASYNC_RECV_TAIL(io
, async_seek
);
827 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
828 struct ntvfs_request
*req
,
831 struct cvfs_private
*p
= ntvfs
->private_data
;
832 struct smbcli_request
*c_req
;
835 switch (io
->generic
.level
) {
836 case RAW_FLUSH_FLUSH
:
840 io
->generic
.in
.file
.fnum
= 0xFFFF;
843 return NT_STATUS_INVALID_LEVEL
;
846 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
847 return smb_raw_flush(p
->tree
, io
);
850 c_req
= smb_raw_flush_send(p
->tree
, io
);
858 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
859 struct ntvfs_request
*req
, union smb_close
*io
)
861 struct cvfs_private
*p
= ntvfs
->private_data
;
862 struct smbcli_request
*c_req
;
868 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
&&
870 return ntvfs_map_close(ntvfs
, req
, io
);
873 if (io
->generic
.level
== RAW_CLOSE_GENERIC
) {
875 io2
.close
.level
= RAW_CLOSE_CLOSE
;
876 io2
.close
.in
.file
= io
->generic
.in
.file
;
877 io2
.close
.in
.write_time
= io
->generic
.in
.write_time
;
882 /* Note, we aren't free-ing f, or it's h here. Should we?
883 even if file-close fails, we'll remove it from the list,
884 what else would we do? Maybe we should not remove until
885 after the proxied call completes? */
886 DLIST_REMOVE(p
->files
, f
);
888 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
889 return smb_raw_close(p
->tree
, io
);
892 c_req
= smb_raw_close_send(p
->tree
, io
);
898 exit - closing files open by the pid
900 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
901 struct ntvfs_request
*req
)
903 struct cvfs_private
*p
= ntvfs
->private_data
;
904 struct smbcli_request
*c_req
;
908 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
909 return smb_raw_exit(p
->tree
->session
);
912 c_req
= smb_raw_exit_send(p
->tree
->session
);
918 logoff - closing files open by the user
920 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
921 struct ntvfs_request
*req
)
923 /* we can't do this right in the cifs backend .... */
928 setup for an async call - nothing to do yet
930 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
931 struct ntvfs_request
*req
,
940 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
941 struct ntvfs_request
*req
)
943 struct cvfs_private
*p
= ntvfs
->private_data
;
944 struct async_info
*a
;
946 /* find the matching request */
947 for (a
=p
->pending
;a
;a
=a
->next
) {
954 return NT_STATUS_INVALID_PARAMETER
;
957 return smb_raw_ntcancel(a
->c_req
);
963 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
964 struct ntvfs_request
*req
, union smb_lock
*io
)
966 struct cvfs_private
*p
= ntvfs
->private_data
;
967 struct smbcli_request
*c_req
;
971 if (io
->generic
.level
!= RAW_LOCK_GENERIC
&&
973 return ntvfs_map_lock(ntvfs
, req
, io
);
977 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
978 return smb_raw_lock(p
->tree
, io
);
981 c_req
= smb_raw_lock_send(p
->tree
, io
);
986 set info on a open file
988 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
989 struct ntvfs_request
*req
,
990 union smb_setfileinfo
*io
)
992 struct cvfs_private
*p
= ntvfs
->private_data
;
993 struct smbcli_request
*c_req
;
997 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
998 return smb_raw_setfileinfo(p
->tree
, io
);
1000 c_req
= smb_raw_setfileinfo_send(p
->tree
, io
);
1007 a handler for async fsinfo replies
1009 static void async_fsinfo(struct smbcli_request
*c_req
)
1011 struct async_info
*async
= c_req
->async
.private_data
;
1012 struct ntvfs_request
*req
= async
->req
;
1013 req
->async_states
->status
= smb_raw_fsinfo_recv(c_req
, req
, async
->parms
);
1015 req
->async_states
->send_fn(req
);
1019 return filesystem space info
1021 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
1022 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
1024 struct cvfs_private
*p
= ntvfs
->private_data
;
1025 struct smbcli_request
*c_req
;
1029 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1030 return smb_raw_fsinfo(p
->tree
, req
, fs
);
1033 c_req
= smb_raw_fsinfo_send(p
->tree
, req
, fs
);
1035 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
1039 return print queue info
1041 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
1042 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
1044 return NT_STATUS_NOT_SUPPORTED
;
1048 list files in a directory matching a wildcard pattern
1050 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
1051 struct ntvfs_request
*req
, union smb_search_first
*io
,
1052 void *search_private
,
1053 bool (*callback
)(void *, const union smb_search_data
*))
1055 struct cvfs_private
*p
= ntvfs
->private_data
;
1059 return smb_raw_search_first(p
->tree
, req
, io
, search_private
, callback
);
1062 /* continue a search */
1063 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
1064 struct ntvfs_request
*req
, union smb_search_next
*io
,
1065 void *search_private
,
1066 bool (*callback
)(void *, const union smb_search_data
*))
1068 struct cvfs_private
*p
= ntvfs
->private_data
;
1072 return smb_raw_search_next(p
->tree
, req
, io
, search_private
, callback
);
1075 /* close a search */
1076 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
1077 struct ntvfs_request
*req
, union smb_search_close
*io
)
1079 struct cvfs_private
*p
= ntvfs
->private_data
;
1083 return smb_raw_search_close(p
->tree
, io
);
1087 a handler for async trans2 replies
1089 static void async_trans2(struct smbcli_request
*c_req
)
1091 struct async_info
*async
= c_req
->async
.private_data
;
1092 struct ntvfs_request
*req
= async
->req
;
1093 req
->async_states
->status
= smb_raw_trans2_recv(c_req
, req
, async
->parms
);
1095 req
->async_states
->send_fn(req
);
1099 static NTSTATUS
cvfs_trans2(struct ntvfs_module_context
*ntvfs
,
1100 struct ntvfs_request
*req
,
1101 struct smb_trans2
*trans2
)
1103 struct cvfs_private
*p
= ntvfs
->private_data
;
1104 struct smbcli_request
*c_req
;
1106 if (p
->map_trans2
) {
1107 return NT_STATUS_NOT_IMPLEMENTED
;
1112 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1113 return smb_raw_trans2(p
->tree
, req
, trans2
);
1116 c_req
= smb_raw_trans2_send(p
->tree
, trans2
);
1118 ASYNC_RECV_TAIL(trans2
, async_trans2
);
1122 /* SMBtrans - not used on file shares */
1123 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
1124 struct ntvfs_request
*req
,
1125 struct smb_trans2
*trans2
)
1127 return NT_STATUS_ACCESS_DENIED
;
1131 a handler for async change notify replies
1133 static void async_changenotify(struct smbcli_request
*c_req
)
1135 struct async_info
*async
= c_req
->async
.private_data
;
1136 struct ntvfs_request
*req
= async
->req
;
1137 req
->async_states
->status
= smb_raw_changenotify_recv(c_req
, req
, async
->parms
);
1139 req
->async_states
->send_fn(req
);
1142 /* change notify request - always async */
1143 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
1144 struct ntvfs_request
*req
,
1145 union smb_notify
*io
)
1147 struct cvfs_private
*p
= ntvfs
->private_data
;
1148 struct smbcli_request
*c_req
;
1149 int saved_timeout
= p
->transport
->options
.request_timeout
;
1150 struct cvfs_file
*f
;
1152 if (io
->nttrans
.level
!= RAW_NOTIFY_NTTRANS
) {
1153 return NT_STATUS_NOT_IMPLEMENTED
;
1158 f
= ntvfs_handle_get_backend_data(io
->nttrans
.in
.file
.ntvfs
, ntvfs
);
1159 if (!f
) return NT_STATUS_INVALID_HANDLE
;
1160 io
->nttrans
.in
.file
.fnum
= f
->fnum
;
1162 /* this request doesn't make sense unless its async */
1163 if (!(req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1164 return NT_STATUS_INVALID_PARAMETER
;
1167 /* we must not timeout on notify requests - they wait
1169 p
->transport
->options
.request_timeout
= 0;
1171 c_req
= smb_raw_changenotify_send(p
->tree
, io
);
1173 p
->transport
->options
.request_timeout
= saved_timeout
;
1175 ASYNC_RECV_TAIL(io
, async_changenotify
);
1179 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1181 NTSTATUS
ntvfs_cifs_init(void)
1184 struct ntvfs_ops ops
;
1185 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
1189 /* fill in the name and type */
1191 ops
.type
= NTVFS_DISK
;
1193 /* fill in all the operations */
1194 ops
.connect_fn
= cvfs_connect
;
1195 ops
.disconnect_fn
= cvfs_disconnect
;
1196 ops
.unlink_fn
= cvfs_unlink
;
1197 ops
.chkpath_fn
= cvfs_chkpath
;
1198 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
1199 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
1200 ops
.open_fn
= cvfs_open
;
1201 ops
.mkdir_fn
= cvfs_mkdir
;
1202 ops
.rmdir_fn
= cvfs_rmdir
;
1203 ops
.rename_fn
= cvfs_rename
;
1204 ops
.copy_fn
= cvfs_copy
;
1205 ops
.ioctl_fn
= cvfs_ioctl
;
1206 ops
.read_fn
= cvfs_read
;
1207 ops
.write_fn
= cvfs_write
;
1208 ops
.seek_fn
= cvfs_seek
;
1209 ops
.flush_fn
= cvfs_flush
;
1210 ops
.close_fn
= cvfs_close
;
1211 ops
.exit_fn
= cvfs_exit
;
1212 ops
.lock_fn
= cvfs_lock
;
1213 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
1214 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
1215 ops
.fsinfo_fn
= cvfs_fsinfo
;
1216 ops
.lpq_fn
= cvfs_lpq
;
1217 ops
.search_first_fn
= cvfs_search_first
;
1218 ops
.search_next_fn
= cvfs_search_next
;
1219 ops
.search_close_fn
= cvfs_search_close
;
1220 ops
.trans_fn
= cvfs_trans
;
1221 ops
.logoff_fn
= cvfs_logoff
;
1222 ops
.async_setup_fn
= cvfs_async_setup
;
1223 ops
.cancel_fn
= cvfs_cancel
;
1224 ops
.notify_fn
= cvfs_notify
;
1225 ops
.trans2_fn
= cvfs_trans2
;
1227 /* register ourselves with the NTVFS subsystem. We register
1228 under the name 'cifs'. */
1229 ret
= ntvfs_register(&ops
, &vers
);
1231 if (!NT_STATUS_IS_OK(ret
)) {
1232 DEBUG(0,("Failed to register CIFS backend!\n"));