X-Git-Url: http://git.samba.org/?p=amitay%2Fsamba.git;a=blobdiff_plain;f=source4%2Fntvfs%2Fcifs%2Fvfs_cifs.c;h=91ca08d2de0b68b52d85058640bedb4c63b00e3f;hp=50aa58d6fb54ad29d5861c3366c28966523ad3fd;hb=4031ff121d7f9a6b1dab8bd8ed54b47195f03955;hpb=9225c02aee19478fc4825c4b798a6757d140b5c0 diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 50aa58d6fb5..91ca08d2de0 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -8,7 +8,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,8 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ /* this implements a CIFS->CIFS NTVFS filesystem backend. @@ -27,12 +26,20 @@ #include "includes.h" #include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" #include "libcli/smb_composite/smb_composite.h" -#include "smb_server/smb_server.h" -#include "smbd/service_stream.h" #include "auth/auth.h" +#include "auth/credentials/credentials.h" #include "ntvfs/ntvfs.h" -#include "include/dlinklist.h" +#include "../lib/util/dlinklist.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" + +struct cvfs_file { + struct cvfs_file *prev, *next; + uint16_t fnum; + struct ntvfs_handle *h; +}; /* this is stored in ntvfs_private */ struct cvfs_private { @@ -40,7 +47,9 @@ struct cvfs_private { struct smbcli_transport *transport; struct ntvfs_module_context *ntvfs; struct async_info *pending; - BOOL map_generic; + struct cvfs_file *files; + bool map_generic; + bool map_trans2; }; @@ -50,63 +59,145 @@ struct async_info { struct cvfs_private *cvfs; struct ntvfs_request *req; struct smbcli_request *c_req; + struct cvfs_file *f; void *parms; }; -#define SETUP_PID private->tree->session->pid = req->smbpid +NTSTATUS ntvfs_cifs_init(void); + +#define CHECK_UPSTREAM_OPEN do { \ + if (! p->transport->socket->sock) { \ + req->async_states->state|=NTVFS_ASYNC_STATE_CLOSE; \ + return NT_STATUS_CONNECTION_DISCONNECTED; \ + } \ +} while(0) + +#define SETUP_PID do { \ + p->tree->session->pid = req->smbpid; \ + CHECK_UPSTREAM_OPEN; \ +} while(0) + +#define SETUP_FILE_HERE(f) do { \ + f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \ + if (!f) return NT_STATUS_INVALID_HANDLE; \ + io->generic.in.file.fnum = f->fnum; \ +} while (0) + +#define SETUP_FILE do { \ + struct cvfs_file *f; \ + SETUP_FILE_HERE(f); \ +} while (0) + +#define SETUP_PID_AND_FILE do { \ + SETUP_PID; \ + SETUP_FILE; \ +} while (0) + +#define CIFS_SERVER "cifs:server" +#define CIFS_USER "cifs:user" +#define CIFS_PASSWORD "cifs:password" +#define CIFS_DOMAIN "cifs:domain" +#define CIFS_SHARE "cifs:share" +#define CIFS_USE_MACHINE_ACCT "cifs:use-machine-account" +#define CIFS_USE_S4U2PROXY "cifs:use-s4u2proxy" +#define CIFS_MAP_GENERIC "cifs:map-generic" +#define CIFS_MAP_TRANS2 "cifs:map-trans2" + +#define CIFS_USE_MACHINE_ACCT_DEFAULT false +#define CIFS_USE_S4U2PROXY_DEFAULT false +#define CIFS_MAP_GENERIC_DEFAULT false +#define CIFS_MAP_TRANS2_DEFAULT true /* a handler for oplock break events from the server - these need to be passed along to the client */ -static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private) +static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private) { - struct cvfs_private *private = p_private; + struct cvfs_private *p = p_private; NTSTATUS status; + struct ntvfs_handle *h = NULL; + struct cvfs_file *f; + + for (f=p->files; f; f=f->next) { + if (f->fnum != fnum) continue; + h = f->h; + break; + } + + if (!h) { + DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level, fnum)); + return true; + } DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum)); - status = ntvfs_send_oplock_break(private->ntvfs, fnum, level); - if (!NT_STATUS_IS_OK(status)) return False; - return True; + status = ntvfs_send_oplock_break(p->ntvfs, h, level); + if (!NT_STATUS_IS_OK(status)) return false; + return true; } /* connect to a share - used when a tree_connect operation comes in. */ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, const char *sharename) + struct ntvfs_request *req, + union smb_tcon *tcon) { NTSTATUS status; - struct cvfs_private *private; + struct cvfs_private *p; const char *host, *user, *pass, *domain, *remote_share; struct smb_composite_connect io; struct composite_context *creq; - int snum = ntvfs->ctx->config.snum; + struct share_config *scfg = ntvfs->ctx->config; struct cli_credentials *credentials; - BOOL machine_account; + bool machine_account; + bool s4u2proxy; + const char* sharename; + + switch (tcon->generic.level) { + case RAW_TCON_TCON: + sharename = tcon->tcon.in.service; + break; + case RAW_TCON_TCONX: + sharename = tcon->tconx.in.path; + break; + case RAW_TCON_SMB2: + sharename = tcon->smb2.in.path; + break; + default: + return NT_STATUS_INVALID_LEVEL; + } + + if (strncmp(sharename, "\\\\", 2) == 0) { + char *str = strchr(sharename+2, '\\'); + if (str) { + sharename = str + 1; + } + } /* Here we need to determine which server to connect to. * For now we use parametric options, type cifs. * Later we will use security=server and auth_server.c. */ - host = lp_parm_string(snum, "cifs", "server"); - user = lp_parm_string(snum, "cifs", "user"); - pass = lp_parm_string(snum, "cifs", "password"); - domain = lp_parm_string(snum, "cifs", "domain"); - remote_share = lp_parm_string(snum, "cifs", "share"); + host = share_string_option(scfg, CIFS_SERVER, NULL); + user = share_string_option(scfg, CIFS_USER, NULL); + pass = share_string_option(scfg, CIFS_PASSWORD, NULL); + domain = share_string_option(scfg, CIFS_DOMAIN, NULL); + remote_share = share_string_option(scfg, CIFS_SHARE, NULL); if (!remote_share) { remote_share = sharename; } - machine_account = lp_parm_bool(snum, "cifs", "use_machine_account", False); + machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT); + s4u2proxy = share_bool_option(scfg, CIFS_USE_S4U2PROXY, CIFS_USE_S4U2PROXY_DEFAULT); - private = talloc_zero(ntvfs, struct cvfs_private); - if (!private) { + p = talloc_zero(ntvfs, struct cvfs_private); + if (!p) { return NT_STATUS_NO_MEMORY; } - ntvfs->private_data = private; + ntvfs->private_data = p; if (!host) { DEBUG(1,("CIFS backend: You must supply server\n")); @@ -115,11 +206,11 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, if (user && pass) { DEBUG(5, ("CIFS backend: Using specified password\n")); - credentials = cli_credentials_init(private); + credentials = cli_credentials_init(p); if (!credentials) { return NT_STATUS_NO_MEMORY; } - cli_credentials_set_conf(credentials); + cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); cli_credentials_set_username(credentials, user, CRED_SPECIFIED); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); @@ -127,53 +218,114 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, cli_credentials_set_password(credentials, pass, CRED_SPECIFIED); } else if (machine_account) { DEBUG(5, ("CIFS backend: Using machine account\n")); - credentials = cli_credentials_init(private); - cli_credentials_set_conf(credentials); + credentials = cli_credentials_init(p); + cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); } - status = cli_credentials_set_machine_account(credentials); + status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { return status; } } else if (req->session_info->credentials) { DEBUG(5, ("CIFS backend: Using delegated credentials\n")); credentials = req->session_info->credentials; + } else if (s4u2proxy) { + struct ccache_container *ccc = NULL; + const char *err_str = NULL; + int ret; + char *impersonate_principal; + char *self_service; + char *target_service; + + impersonate_principal = talloc_asprintf(req, "%s@%s", + req->session_info->info->account_name, + req->session_info->info->domain_name); + + self_service = talloc_asprintf(req, "cifs/%s", + lpcfg_netbios_name(ntvfs->ctx->lp_ctx)); + + target_service = talloc_asprintf(req, "cifs/%s", host); + + DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n")); + + credentials = cli_credentials_init(p); + cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); + if (domain) { + cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); + } + status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); + cli_credentials_set_impersonate_principal(credentials, + impersonate_principal, + self_service); + cli_credentials_set_target_service(credentials, target_service); + ret = cli_credentials_get_ccache(credentials, + ntvfs->ctx->event_ctx, + ntvfs->ctx->lp_ctx, + &ccc, + &err_str); + if (ret != 0) { + status = NT_STATUS_CROSSREALM_DELEGATION_FAILURE; + DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n", + ret, err_str, nt_errstr(status))); + return status; + } + } else { - DEBUG(1,("CIFS backend: You must supply server, user and password and or have delegated credentials\n")); - return NT_STATUS_INVALID_PARAMETER; + DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n")); + return NT_STATUS_INTERNAL_ERROR; } /* connect to the server, using the smbd event context */ io.in.dest_host = host; - io.in.port = 0; + io.in.dest_ports = lpcfg_smb_ports(ntvfs->ctx->lp_ctx); + io.in.socket_options = lpcfg_socket_options(ntvfs->ctx->lp_ctx); io.in.called_name = host; io.in.credentials = credentials; - io.in.fallback_to_anonymous = False; - io.in.workgroup = lp_workgroup(); + io.in.fallback_to_anonymous = false; + io.in.workgroup = lpcfg_workgroup(ntvfs->ctx->lp_ctx); io.in.service = remote_share; io.in.service_type = "?????"; - - creq = smb_composite_connect_send(&io, private, ntvfs->ctx->event_ctx); - status = smb_composite_connect_recv(creq, private); + io.in.gensec_settings = lpcfg_gensec_settings(p, ntvfs->ctx->lp_ctx); + lpcfg_smbcli_options(ntvfs->ctx->lp_ctx, &io.in.options); + lpcfg_smbcli_session_options(ntvfs->ctx->lp_ctx, &io.in.session_options); + + if (!(ntvfs->ctx->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS)) { + io.in.options.use_level2_oplocks = false; + } + + creq = smb_composite_connect_send(&io, p, + lpcfg_resolve_context(ntvfs->ctx->lp_ctx), + ntvfs->ctx->event_ctx); + status = smb_composite_connect_recv(creq, p); NT_STATUS_NOT_OK_RETURN(status); - private->tree = io.out.tree; + p->tree = io.out.tree; - private->transport = private->tree->session->transport; + p->transport = p->tree->session->transport; SETUP_PID; - private->ntvfs = ntvfs; + p->ntvfs = ntvfs; ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); + if (tcon->generic.level == RAW_TCON_TCONX) { + tcon->tconx.out.fs_type = ntvfs->ctx->fs_type; + tcon->tconx.out.dev_type = ntvfs->ctx->dev_type; + } + /* we need to receive oplock break requests from the server */ - smbcli_oplock_handler(private->transport, oplock_handler, private); + smbcli_oplock_handler(p->transport, oplock_handler, p); - private->map_generic = lp_parm_bool(ntvfs->ctx->config.snum, - "cifs", "mapgeneric", False); + p->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT); + + p->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT); return NT_STATUS_OK; } @@ -183,9 +335,17 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, */ static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; + struct async_info *a, *an; + + /* first cleanup pending requests */ + for (a=p->pending; a; a = an) { + an = a->next; + smbcli_request_destroy(a->c_req); + talloc_free(a); + } - talloc_free(private); + talloc_free(p); ntvfs->private_data = NULL; return NT_STATUS_OK; @@ -194,9 +354,8 @@ static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs) /* destroy an async info structure */ -static int async_info_destructor(void *p) +static int async_info_destructor(struct async_info *async) { - struct async_info *async = talloc_get_type(p, struct async_info); DLIST_REMOVE(async->cvfs->pending, async); return 0; } @@ -208,15 +367,16 @@ static int async_info_destructor(void *p) */ static void async_simple(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smbcli_request_simple_recv(c_req); + talloc_free(async); req->async_states->send_fn(req); } /* save some typing for the simple functions */ -#define ASYNC_RECV_TAIL(io, async_fn) do { \ +#define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \ if (!c_req) return NT_STATUS_UNSUCCESSFUL; \ { \ struct async_info *async; \ @@ -224,10 +384,11 @@ static void async_simple(struct smbcli_request *c_req) if (!async) return NT_STATUS_NO_MEMORY; \ async->parms = io; \ async->req = req; \ - async->cvfs = private; \ + async->f = file; \ + async->cvfs = p; \ async->c_req = c_req; \ - DLIST_ADD(private->pending, async); \ - c_req->async.private = async; \ + DLIST_ADD(p->pending, async); \ + c_req->async.private_data = async; \ talloc_set_destructor(async, async_info_destructor); \ } \ c_req->async.fn = async_fn; \ @@ -235,6 +396,8 @@ static void async_simple(struct smbcli_request *c_req) return NT_STATUS_OK; \ } while (0) +#define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL) + #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple) /* @@ -244,7 +407,7 @@ static void async_simple(struct smbcli_request *c_req) static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_unlink *unl) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; @@ -252,10 +415,10 @@ static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, /* see if the front end will allow us to perform this function asynchronously. */ if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_unlink(private->tree, unl); + return smb_raw_unlink(p->tree, unl); } - c_req = smb_raw_unlink_send(private->tree, unl); + c_req = smb_raw_unlink_send(p->tree, unl); SIMPLE_ASYNC_TAIL; } @@ -265,9 +428,10 @@ static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, */ static void async_ioctl(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -275,20 +439,20 @@ static void async_ioctl(struct smbcli_request *c_req) ioctl interface */ static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_ioctl *io) + struct ntvfs_request *req, union smb_ioctl *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; + SETUP_PID_AND_FILE; /* see if the front end will allow us to perform this function asynchronously. */ if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_ioctl(private->tree, req, io); + return smb_raw_ioctl(p->tree, req, io); } - c_req = smb_raw_ioctl_send(private->tree, io); + c_req = smb_raw_ioctl_send(p->tree, io); ASYNC_RECV_TAIL(io, async_ioctl); } @@ -297,18 +461,18 @@ static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, check if a directory exists */ static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_chkpath *cp) + struct ntvfs_request *req, union smb_chkpath *cp) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_chkpath(private->tree, cp); + return smb_raw_chkpath(p->tree, cp); } - c_req = smb_raw_chkpath_send(private->tree, cp); + c_req = smb_raw_chkpath_send(p->tree, cp); SIMPLE_ASYNC_TAIL; } @@ -318,9 +482,10 @@ static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, */ static void async_qpathinfo(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -328,18 +493,18 @@ static void async_qpathinfo(struct smbcli_request *c_req) return info on a pathname */ static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_fileinfo *info) + struct ntvfs_request *req, union smb_fileinfo *info) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_pathinfo(private->tree, req, info); + return smb_raw_pathinfo(p->tree, req, info); } - c_req = smb_raw_pathinfo_send(private->tree, info); + c_req = smb_raw_pathinfo_send(p->tree, info); ASYNC_RECV_TAIL(info, async_qpathinfo); } @@ -349,9 +514,10 @@ static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, */ static void async_qfileinfo(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -359,20 +525,20 @@ static void async_qfileinfo(struct smbcli_request *c_req) query info on a open file */ static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_fileinfo *info) + struct ntvfs_request *req, union smb_fileinfo *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; + SETUP_PID_AND_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_fileinfo(private->tree, req, info); + return smb_raw_fileinfo(p->tree, req, io); } - c_req = smb_raw_fileinfo_send(private->tree, info); + c_req = smb_raw_fileinfo_send(p->tree, io); - ASYNC_RECV_TAIL(info, async_qfileinfo); + ASYNC_RECV_TAIL(io, async_qfileinfo); } @@ -380,18 +546,18 @@ static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, set info on a pathname */ static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_setfileinfo *st) + struct ntvfs_request *req, union smb_setfileinfo *st) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_setpathinfo(private->tree, st); + return smb_raw_setpathinfo(p->tree, st); } - c_req = smb_raw_setpathinfo_send(private->tree, st); + c_req = smb_raw_setpathinfo_send(p->tree, st); SIMPLE_ASYNC_TAIL; } @@ -402,9 +568,23 @@ static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, */ static void async_open(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; + struct cvfs_private *cvfs = async->cvfs; struct ntvfs_request *req = async->req; - req->async_states->status = smb_raw_open_recv(c_req, req, async->parms); + struct cvfs_file *f = async->f; + union smb_open *io = async->parms; + union smb_handle *file; + talloc_free(async); + req->async_states->status = smb_raw_open_recv(c_req, req, io); + SMB_OPEN_OUT_FILE(io, file); + f->fnum = file->fnum; + file->ntvfs = NULL; + if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed; + req->async_states->status = ntvfs_handle_set_backend_data(f->h, cvfs->ntvfs, f); + if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed; + file->ntvfs = f->h; + DLIST_ADD(cvfs->files, f); +failed: req->async_states->send_fn(req); } @@ -412,43 +592,66 @@ static void async_open(struct smbcli_request *c_req) open a file */ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_open *io) + struct ntvfs_request *req, union smb_open *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; + struct ntvfs_handle *h; + struct cvfs_file *f; + NTSTATUS status; SETUP_PID; if (io->generic.level != RAW_OPEN_GENERIC && - private->map_generic) { + p->map_generic) { return ntvfs_map_open(ntvfs, req, io); } + status = ntvfs_handle_new(ntvfs, req, &h); + NT_STATUS_NOT_OK_RETURN(status); + + f = talloc_zero(h, struct cvfs_file); + NT_STATUS_HAVE_NO_MEMORY(f); + f->h = h; + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_open(private->tree, req, io); + union smb_handle *file; + + status = smb_raw_open(p->tree, req, io); + NT_STATUS_NOT_OK_RETURN(status); + + SMB_OPEN_OUT_FILE(io, file); + f->fnum = file->fnum; + file->ntvfs = NULL; + status = ntvfs_handle_set_backend_data(f->h, p->ntvfs, f); + NT_STATUS_NOT_OK_RETURN(status); + file->ntvfs = f->h; + DLIST_ADD(p->files, f); + + return NT_STATUS_OK; } - c_req = smb_raw_open_send(private->tree, io); + c_req = smb_raw_open_send(p->tree, io); - ASYNC_RECV_TAIL(io, async_open); + ASYNC_RECV_TAIL_F(io, async_open, f); } /* create a directory */ static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_mkdir *md) + struct ntvfs_request *req, union smb_mkdir *md) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_mkdir(private->tree, md); + return smb_raw_mkdir(p->tree, md); } - c_req = smb_raw_mkdir_send(private->tree, md); + c_req = smb_raw_mkdir_send(p->tree, md); SIMPLE_ASYNC_TAIL; } @@ -457,17 +660,17 @@ static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, remove a directory */ static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, struct smb_rmdir *rd) + struct ntvfs_request *req, struct smb_rmdir *rd) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_rmdir(private->tree, rd); + return smb_raw_rmdir(p->tree, rd); } - c_req = smb_raw_rmdir_send(private->tree, rd); + c_req = smb_raw_rmdir_send(p->tree, rd); SIMPLE_ASYNC_TAIL; } @@ -476,18 +679,25 @@ static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, rename a set of files */ static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_rename *ren) + struct ntvfs_request *req, union smb_rename *ren) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; + if (ren->nttrans.level == RAW_RENAME_NTTRANS) { + struct cvfs_file *f; + f = ntvfs_handle_get_backend_data(ren->nttrans.in.file.ntvfs, ntvfs); + if (!f) return NT_STATUS_INVALID_HANDLE; + ren->nttrans.in.file.fnum = f->fnum; + } + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_rename(private->tree, ren); + return smb_raw_rename(p->tree, ren); } - c_req = smb_raw_rename_send(private->tree, ren); + c_req = smb_raw_rename_send(p->tree, ren); SIMPLE_ASYNC_TAIL; } @@ -496,7 +706,7 @@ static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, copy a set of files */ static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, struct smb_copy *cp) + struct ntvfs_request *req, struct smb_copy *cp) { return NT_STATUS_NOT_SUPPORTED; } @@ -506,9 +716,10 @@ static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, */ static void async_read(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_read_recv(c_req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -516,25 +727,27 @@ static void async_read(struct smbcli_request *c_req) read from a file */ static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_read *rd) + struct ntvfs_request *req, union smb_read *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; - if (rd->generic.level != RAW_READ_GENERIC && - private->map_generic) { - return ntvfs_map_read(ntvfs, req, rd); + if (io->generic.level != RAW_READ_GENERIC && + p->map_generic) { + return ntvfs_map_read(ntvfs, req, io); } + SETUP_FILE; + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_read(private->tree, rd); + return smb_raw_read(p->tree, io); } - c_req = smb_raw_read_send(private->tree, rd); + c_req = smb_raw_read_send(p->tree, io); - ASYNC_RECV_TAIL(rd, async_read); + ASYNC_RECV_TAIL(io, async_read); } /* @@ -542,9 +755,10 @@ static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, */ static void async_write(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_write_recv(c_req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -552,25 +766,26 @@ static void async_write(struct smbcli_request *c_req) write to a file */ static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_write *wr) + struct ntvfs_request *req, union smb_write *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; - if (wr->generic.level != RAW_WRITE_GENERIC && - private->map_generic) { - return ntvfs_map_write(ntvfs, req, wr); + if (io->generic.level != RAW_WRITE_GENERIC && + p->map_generic) { + return ntvfs_map_write(ntvfs, req, io); } + SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_write(private->tree, wr); + return smb_raw_write(p->tree, io); } - c_req = smb_raw_write_send(private->tree, wr); + c_req = smb_raw_write_send(p->tree, io); - ASYNC_RECV_TAIL(wr, async_write); + ASYNC_RECV_TAIL(io, async_write); } /* @@ -578,9 +793,10 @@ static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, */ static void async_seek(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_seek_recv(c_req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -591,16 +807,16 @@ static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_seek *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; + SETUP_PID_AND_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_seek(private->tree, io); + return smb_raw_seek(p->tree, io); } - c_req = smb_raw_seek_send(private->tree, io); + c_req = smb_raw_seek_send(p->tree, io); ASYNC_RECV_TAIL(io, async_seek); } @@ -612,16 +828,26 @@ static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_flush *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; + switch (io->generic.level) { + case RAW_FLUSH_FLUSH: + SETUP_FILE; + break; + case RAW_FLUSH_ALL: + io->generic.in.file.fnum = 0xFFFF; + break; + case RAW_FLUSH_SMB2: + return NT_STATUS_INVALID_LEVEL; + } if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_flush(private->tree, io); + return smb_raw_flush(p->tree, io); } - c_req = smb_raw_flush_send(private->tree, io); + c_req = smb_raw_flush_send(p->tree, io); SIMPLE_ASYNC_TAIL; } @@ -630,23 +856,40 @@ static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, close a file */ static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_close *io) + struct ntvfs_request *req, union smb_close *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; + struct cvfs_file *f; + union smb_close io2; SETUP_PID; if (io->generic.level != RAW_CLOSE_GENERIC && - private->map_generic) { + p->map_generic) { return ntvfs_map_close(ntvfs, req, io); } + if (io->generic.level == RAW_CLOSE_GENERIC) { + ZERO_STRUCT(io2); + io2.close.level = RAW_CLOSE_CLOSE; + io2.close.in.file = io->generic.in.file; + io2.close.in.write_time = io->generic.in.write_time; + io = &io2; + } + + SETUP_FILE_HERE(f); + /* Note, we aren't free-ing f, or it's h here. Should we? + even if file-close fails, we'll remove it from the list, + what else would we do? Maybe we should not remove until + after the proxied call completes? */ + DLIST_REMOVE(p->files, f); + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_close(private->tree, io); + return smb_raw_close(p->tree, io); } - c_req = smb_raw_close_send(private->tree, io); + c_req = smb_raw_close_send(p->tree, io); SIMPLE_ASYNC_TAIL; } @@ -655,18 +898,18 @@ static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, exit - closing files open by the pid */ static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req) + struct ntvfs_request *req) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_exit(private->tree->session); + return smb_raw_exit(p->tree->session); } - c_req = smb_raw_exit_send(private->tree->session); + c_req = smb_raw_exit_send(p->tree->session); SIMPLE_ASYNC_TAIL; } @@ -675,7 +918,7 @@ static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, logoff - closing files open by the user */ static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req) + struct ntvfs_request *req) { /* we can't do this right in the cifs backend .... */ return NT_STATUS_OK; @@ -686,7 +929,7 @@ static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, */ static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, - void *private) + void *private_data) { return NT_STATUS_OK; } @@ -697,12 +940,12 @@ static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct async_info *a; /* find the matching request */ - for (a=private->pending;a;a=a->next) { - if (a->req->smbmid == req->smbmid) { + for (a=p->pending;a;a=a->next) { + if (a->req == req) { break; } } @@ -718,23 +961,24 @@ static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, lock a byte range */ static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_lock *lck) + struct ntvfs_request *req, union smb_lock *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; - if (lck->generic.level != RAW_LOCK_GENERIC && - private->map_generic) { - return ntvfs_map_lock(ntvfs, req, lck); + if (io->generic.level != RAW_LOCK_GENERIC && + p->map_generic) { + return ntvfs_map_lock(ntvfs, req, io); } + SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_lock(private->tree, lck); + return smb_raw_lock(p->tree, io); } - c_req = smb_raw_lock_send(private->tree, lck); + c_req = smb_raw_lock_send(p->tree, io); SIMPLE_ASYNC_TAIL; } @@ -743,17 +987,17 @@ static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, */ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, - union smb_setfileinfo *info) + union smb_setfileinfo *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; + SETUP_PID_AND_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_setfileinfo(private->tree, info); + return smb_raw_setfileinfo(p->tree, io); } - c_req = smb_raw_setfileinfo_send(private->tree, info); + c_req = smb_raw_setfileinfo_send(p->tree, io); SIMPLE_ASYNC_TAIL; } @@ -764,9 +1008,10 @@ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, */ static void async_fsinfo(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -774,18 +1019,18 @@ static void async_fsinfo(struct smbcli_request *c_req) return filesystem space info */ static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_fsinfo *fs) + struct ntvfs_request *req, union smb_fsinfo *fs) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_fsinfo(private->tree, req, fs); + return smb_raw_fsinfo(p->tree, req, fs); } - c_req = smb_raw_fsinfo_send(private->tree, req, fs); + c_req = smb_raw_fsinfo_send(p->tree, req, fs); ASYNC_RECV_TAIL(fs, async_fsinfo); } @@ -794,7 +1039,7 @@ static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, return print queue info */ static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, union smb_lpq *lpq) + struct ntvfs_request *req, union smb_lpq *lpq) { return NT_STATUS_NOT_SUPPORTED; } @@ -805,37 +1050,37 @@ static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_first *io, void *search_private, - BOOL (*callback)(void *, union smb_search_data *)) + bool (*callback)(void *, const union smb_search_data *)) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; SETUP_PID; - return smb_raw_search_first(private->tree, req, io, search_private, callback); + return smb_raw_search_first(p->tree, req, io, search_private, callback); } /* continue a search */ static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_next *io, void *search_private, - BOOL (*callback)(void *, union smb_search_data *)) + bool (*callback)(void *, const union smb_search_data *)) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; SETUP_PID; - return smb_raw_search_next(private->tree, req, io, search_private, callback); + return smb_raw_search_next(p->tree, req, io, search_private, callback); } /* close a search */ static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_close *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; SETUP_PID; - return smb_raw_search_close(private->tree, io); + return smb_raw_search_close(p->tree, io); } /* @@ -843,9 +1088,10 @@ static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, */ static void async_trans2(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } @@ -854,16 +1100,20 @@ static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, struct smb_trans2 *trans2) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; + if (p->map_trans2) { + return NT_STATUS_NOT_IMPLEMENTED; + } + SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_trans2(private->tree, req, trans2); + return smb_raw_trans2(p->tree, req, trans2); } - c_req = smb_raw_trans2_send(private->tree, trans2); + c_req = smb_raw_trans2_send(p->tree, trans2); ASYNC_RECV_TAIL(trans2, async_trans2); } @@ -882,23 +1132,33 @@ static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, */ static void async_changenotify(struct smbcli_request *c_req) { - struct async_info *async = c_req->async.private; + struct async_info *async = c_req->async.private_data; struct ntvfs_request *req = async->req; req->async_states->status = smb_raw_changenotify_recv(c_req, req, async->parms); + talloc_free(async); req->async_states->send_fn(req); } /* change notify request - always async */ static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, - struct smb_notify *info) + union smb_notify *io) { - struct cvfs_private *private = ntvfs->private_data; + struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; - int saved_timeout = private->transport->options.request_timeout; + int saved_timeout = p->transport->options.request_timeout; + struct cvfs_file *f; + + if (io->nttrans.level != RAW_NOTIFY_NTTRANS) { + return NT_STATUS_NOT_IMPLEMENTED; + } SETUP_PID; + f = ntvfs_handle_get_backend_data(io->nttrans.in.file.ntvfs, ntvfs); + if (!f) return NT_STATUS_INVALID_HANDLE; + io->nttrans.in.file.fnum = f->fnum; + /* this request doesn't make sense unless its async */ if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return NT_STATUS_INVALID_PARAMETER; @@ -906,13 +1166,13 @@ static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs, /* we must not timeout on notify requests - they wait forever */ - private->transport->options.request_timeout = 0; + p->transport->options.request_timeout = 0; - c_req = smb_raw_changenotify_send(private->tree, info); + c_req = smb_raw_changenotify_send(p->tree, io); - private->transport->options.request_timeout = saved_timeout; + p->transport->options.request_timeout = saved_timeout; - ASYNC_RECV_TAIL(info, async_changenotify); + ASYNC_RECV_TAIL(io, async_changenotify); } /* @@ -922,6 +1182,7 @@ NTSTATUS ntvfs_cifs_init(void) { NTSTATUS ret; struct ntvfs_ops ops; + NTVFS_CURRENT_CRITICAL_SIZES(vers); ZERO_STRUCT(ops); @@ -961,14 +1222,11 @@ NTSTATUS ntvfs_cifs_init(void) ops.async_setup = cvfs_async_setup; ops.cancel = cvfs_cancel; ops.notify = cvfs_notify; - - if (lp_parm_bool(-1, "cifs", "maptrans2", False)) { - ops.trans2 = cvfs_trans2; - } + ops.trans2 = cvfs_trans2; /* register ourselves with the NTVFS subsystem. We register under the name 'cifs'. */ - ret = ntvfs_register(&ops); + ret = ntvfs_register(&ops, &vers); if (!NT_STATUS_IS_OK(ret)) { DEBUG(0,("Failed to register CIFS backend!\n"));