From ca3257b286ed2e1b87a7d56ba290d01cd2078023 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 15 May 2008 10:57:22 +1000 Subject: started new vfs_smb2 module This new module is based on the vfs_cifs module. The idea is to create a backend which maps SMB requests to a SMB2 server. This will allow existing test suites for SMB to be run against our SMB2 client and server code. It will also help validate our SMB2 client library, probably leading to some API changes to make it flexible enough (This used to be commit 6ea8295a64ff5425def11b0d1cd988ef000320be) --- source4/ntvfs/config.mk | 14 + source4/ntvfs/ntvfs_base.c | 1 + source4/ntvfs/smb2/vfs_smb2.c | 1137 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1152 insertions(+) create mode 100644 source4/ntvfs/smb2/vfs_smb2.c diff --git a/source4/ntvfs/config.mk b/source4/ntvfs/config.mk index 93cbf64d8f..ceb952d25c 100644 --- a/source4/ntvfs/config.mk +++ b/source4/ntvfs/config.mk @@ -16,6 +16,20 @@ PRIVATE_DEPENDENCIES = \ ntvfs_cifs_OBJ_FILES = ntvfs/cifs/vfs_cifs.o + +################################################ +# Start MODULE ntvfs_smb2 +[MODULE::ntvfs_smb2] +INIT_FUNCTION = ntvfs_smb2_init +SUBSYSTEM = ntvfs +PRIVATE_DEPENDENCIES = \ + LIBCLI_SMB LIBCLI_RAW +# End MODULE ntvfs_smb2 +################################################ + +ntvfs_smb2_OBJ_FILES = ntvfs/smb2/vfs_smb2.o + + ################################################ # Start MODULE ntvfs_simple [MODULE::ntvfs_simple] diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c index 3706cd172c..6de13e4a0a 100644 --- a/source4/ntvfs/ntvfs_base.c +++ b/source4/ntvfs/ntvfs_base.c @@ -205,6 +205,7 @@ NTSTATUS ntvfs_init(struct loadparm_context *lp_ctx) static bool initialized = false; extern NTSTATUS ntvfs_posix_init(void); extern NTSTATUS ntvfs_cifs_init(void); + extern NTSTATUS ntvfs_smb2_init(void); extern NTSTATUS ntvfs_nbench_init(void); extern NTSTATUS ntvfs_unixuid_init(void); extern NTSTATUS ntvfs_ipc_init(void); diff --git a/source4/ntvfs/smb2/vfs_smb2.c b/source4/ntvfs/smb2/vfs_smb2.c new file mode 100644 index 0000000000..f253fcecaf --- /dev/null +++ b/source4/ntvfs/smb2/vfs_smb2.c @@ -0,0 +1,1137 @@ +/* + Unix SMB/CIFS implementation. + + CIFS-to-SMB2 NTVFS filesystem backend + + Copyright (C) Andrew Tridgell 2008 + + largely based on vfs_cifs.c which was + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James J Myers 2003 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . +*/ +/* + this implements a CIFS->CIFS NTVFS filesystem backend. + +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "libcli/smb_composite/smb_composite.h" +#include "auth/auth.h" +#include "auth/credentials/credentials.h" +#include "ntvfs/ntvfs.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 { + struct smbcli_tree *tree; + struct smbcli_transport *transport; + struct ntvfs_module_context *ntvfs; + struct async_info *pending; + struct cvfs_file *files; + bool map_generic; + bool map_trans2; +}; + + +/* a structure used to pass information to an async handler */ +struct async_info { + struct async_info *next, *prev; + 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 + +#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_MAP_GENERIC "cifs:map-generic" +#define CIFS_MAP_TRANS2 "cifs:map-trans2" + +#define CIFS_USE_MACHINE_ACCT_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) +{ + struct cvfs_private *private = p_private; + NTSTATUS status; + struct ntvfs_handle *h = NULL; + struct cvfs_file *f; + + for (f=private->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, 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) +{ + NTSTATUS status; + struct cvfs_private *private; + const char *host, *user, *pass, *domain, *remote_share; + struct smb_composite_connect io; + struct composite_context *creq; + struct share_config *scfg = ntvfs->ctx->config; + + struct cli_credentials *credentials; + bool machine_account; + + /* 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 = 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 = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT); + + private = talloc_zero(ntvfs, struct cvfs_private); + if (!private) { + return NT_STATUS_NO_MEMORY; + } + + ntvfs->private_data = private; + + if (!host) { + DEBUG(1,("CIFS backend: You must supply server\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (user && pass) { + DEBUG(5, ("CIFS backend: Using specified password\n")); + credentials = cli_credentials_init(private); + if (!credentials) { + return NT_STATUS_NO_MEMORY; + } + 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); + } + 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, 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; + } + } else if (req->session_info->credentials) { + DEBUG(5, ("CIFS backend: Using delegated credentials\n")); + credentials = req->session_info->credentials; + } else { + 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_INVALID_PARAMETER; + } + + /* connect to the server, using the smbd event context */ + io.in.dest_host = host; + io.in.dest_ports = lp_smb_ports(ntvfs->ctx->lp_ctx); + io.in.called_name = host; + io.in.credentials = credentials; + io.in.fallback_to_anonymous = false; + io.in.workgroup = lp_workgroup(ntvfs->ctx->lp_ctx); + io.in.service = remote_share; + io.in.service_type = "?????"; + lp_smbcli_options(ntvfs->ctx->lp_ctx, &io.in.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, private, + lp_resolve_context(ntvfs->ctx->lp_ctx), + ntvfs->ctx->event_ctx); + status = smb_composite_connect_recv(creq, private); + NT_STATUS_NOT_OK_RETURN(status); + + private->tree = io.out.tree; + + private->transport = private->tree->session->transport; + SETUP_PID; + private->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); + + /* we need to receive oplock break requests from the server */ + smbcli_oplock_handler(private->transport, oplock_handler, private); + + private->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT); + + private->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT); + + return NT_STATUS_OK; +} + +/* + disconnect from a share +*/ +static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs) +{ + struct cvfs_private *private = ntvfs->private_data; + struct async_info *a, *an; + + /* first cleanup pending requests */ + for (a=private->pending; a; a = an) { + an = a->next; + smbcli_request_destroy(a->c_req); + talloc_free(a); + } + + talloc_free(private); + ntvfs->private_data = NULL; + + return NT_STATUS_OK; +} + +/* + destroy an async info structure +*/ +static int async_info_destructor(struct async_info *async) +{ + DLIST_REMOVE(async->cvfs->pending, async); + return 0; +} + +/* + a handler for simple async replies + this handler can only be used for functions that don't return any + parameters (those that just return a status code) + */ +static void async_simple(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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_F(io, async_fn, file) do { \ + if (!c_req) return NT_STATUS_UNSUCCESSFUL; \ + { \ + struct async_info *async; \ + async = talloc(req, struct async_info); \ + if (!async) return NT_STATUS_NO_MEMORY; \ + async->parms = io; \ + async->req = req; \ + async->f = file; \ + async->cvfs = private; \ + async->c_req = c_req; \ + DLIST_ADD(private->pending, async); \ + c_req->async.private = async; \ + talloc_set_destructor(async, async_info_destructor); \ + } \ + c_req->async.fn = async_fn; \ + req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \ + 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) + +/* + delete a file - the dirtype specifies the file types to include in the search. + The name can contain CIFS wildcards, but rarely does (except with OS/2 clients) +*/ +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 smbcli_request *c_req; + + SETUP_PID; + + /* 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); + } + + c_req = smb_raw_unlink_send(private->tree, unl); + + SIMPLE_ASYNC_TAIL; +} + +/* + a handler for async ioctl replies + */ +static void async_ioctl(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + ioctl interface +*/ +static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_ioctl *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + + 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); + } + + c_req = smb_raw_ioctl_send(private->tree, io); + + ASYNC_RECV_TAIL(io, async_ioctl); +} + +/* + check if a directory exists +*/ +static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_chkpath *cp) +{ + struct cvfs_private *private = 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); + } + + c_req = smb_raw_chkpath_send(private->tree, cp); + + SIMPLE_ASYNC_TAIL; +} + +/* + a handler for async qpathinfo replies + */ +static void async_qpathinfo(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + return info on a pathname +*/ +static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_fileinfo *info) +{ + struct cvfs_private *private = 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); + } + + c_req = smb_raw_pathinfo_send(private->tree, info); + + ASYNC_RECV_TAIL(info, async_qpathinfo); +} + +/* + a handler for async qfileinfo replies + */ +static void async_qfileinfo(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + query info on a open file +*/ +static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_fileinfo *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + + SETUP_PID_AND_FILE; + + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return smb_raw_fileinfo(private->tree, req, io); + } + + c_req = smb_raw_fileinfo_send(private->tree, io); + + ASYNC_RECV_TAIL(io, async_qfileinfo); +} + + +/* + set info on a pathname +*/ +static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_setfileinfo *st) +{ + struct cvfs_private *private = 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); + } + + c_req = smb_raw_setpathinfo_send(private->tree, st); + + SIMPLE_ASYNC_TAIL; +} + + +/* + a handler for async open replies + */ +static void async_open(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + struct cvfs_private *cvfs = async->cvfs; + struct ntvfs_request *req = async->req; + 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); +} + +/* + open a file +*/ +static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_open *io) +{ + struct cvfs_private *private = 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) { + 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)) { + union smb_handle *file; + + status = smb_raw_open(private->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, private->ntvfs, f); + NT_STATUS_NOT_OK_RETURN(status); + file->ntvfs = f->h; + DLIST_ADD(private->files, f); + + return NT_STATUS_OK; + } + + c_req = smb_raw_open_send(private->tree, io); + + 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 cvfs_private *private = 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); + } + + c_req = smb_raw_mkdir_send(private->tree, md); + + SIMPLE_ASYNC_TAIL; +} + +/* + remove a directory +*/ +static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, struct smb_rmdir *rd) +{ + struct cvfs_private *private = 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); + } + c_req = smb_raw_rmdir_send(private->tree, rd); + + SIMPLE_ASYNC_TAIL; +} + +/* + rename a set of files +*/ +static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_rename *ren) +{ + struct cvfs_private *private = 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); + } + + c_req = smb_raw_rename_send(private->tree, ren); + + SIMPLE_ASYNC_TAIL; +} + +/* + copy a set of files +*/ +static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, struct smb_copy *cp) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +/* + a handler for async read replies + */ +static void async_read(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + read from a file +*/ +static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_read *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + + SETUP_PID; + + if (io->generic.level != RAW_READ_GENERIC && + private->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, io); + } + + c_req = smb_raw_read_send(private->tree, io); + + ASYNC_RECV_TAIL(io, async_read); +} + +/* + a handler for async write replies + */ +static void async_write(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + write to a file +*/ +static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_write *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + + SETUP_PID; + + if (io->generic.level != RAW_WRITE_GENERIC && + private->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, io); + } + + c_req = smb_raw_write_send(private->tree, io); + + ASYNC_RECV_TAIL(io, async_write); +} + +/* + a handler for async seek replies + */ +static void async_seek(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + seek in a file +*/ +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 smbcli_request *c_req; + + SETUP_PID_AND_FILE; + + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return smb_raw_seek(private->tree, io); + } + + c_req = smb_raw_seek_send(private->tree, io); + + ASYNC_RECV_TAIL(io, async_seek); +} + +/* + flush a file +*/ +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 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); + } + + c_req = smb_raw_flush_send(private->tree, io); + + SIMPLE_ASYNC_TAIL; +} + +/* + close a file +*/ +static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_close *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + struct cvfs_file *f; + + SETUP_PID; + + if (io->generic.level != RAW_CLOSE_GENERIC && + private->map_generic) { + return ntvfs_map_close(ntvfs, req, io); + } + 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(private->files, f); + + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return smb_raw_close(private->tree, io); + } + + c_req = smb_raw_close_send(private->tree, io); + + SIMPLE_ASYNC_TAIL; +} + +/* + exit - closing files open by the pid +*/ +static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req) +{ + struct cvfs_private *private = 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); + } + + c_req = smb_raw_exit_send(private->tree->session); + + SIMPLE_ASYNC_TAIL; +} + +/* + logoff - closing files open by the user +*/ +static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req) +{ + /* we can't do this right in the cifs backend .... */ + return NT_STATUS_OK; +} + +/* + setup for an async call - nothing to do yet +*/ +static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + void *private) +{ + return NT_STATUS_OK; +} + +/* + cancel an async call +*/ +static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req) +{ + struct cvfs_private *private = ntvfs->private_data; + struct async_info *a; + + /* find the matching request */ + for (a=private->pending;a;a=a->next) { + if (a->req == req) { + break; + } + } + + if (a == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return smb_raw_ntcancel(a->c_req); +} + +/* + lock a byte range +*/ +static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_lock *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + + SETUP_PID; + + if (io->generic.level != RAW_LOCK_GENERIC && + private->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, io); + } + + c_req = smb_raw_lock_send(private->tree, io); + SIMPLE_ASYNC_TAIL; +} + +/* + set info on a open file +*/ +static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_setfileinfo *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + + SETUP_PID_AND_FILE; + + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return smb_raw_setfileinfo(private->tree, io); + } + c_req = smb_raw_setfileinfo_send(private->tree, io); + + SIMPLE_ASYNC_TAIL; +} + + +/* + a handler for async fsinfo replies + */ +static void async_fsinfo(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* + return filesystem space info +*/ +static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_fsinfo *fs) +{ + struct cvfs_private *private = 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); + } + + c_req = smb_raw_fsinfo_send(private->tree, req, fs); + + ASYNC_RECV_TAIL(fs, async_fsinfo); +} + +/* + return print queue info +*/ +static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_lpq *lpq) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +/* + list files in a directory matching a wildcard pattern +*/ +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 *, const union smb_search_data *)) +{ + struct cvfs_private *private = ntvfs->private_data; + + SETUP_PID; + + return smb_raw_search_first(private->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 *, const union smb_search_data *)) +{ + struct cvfs_private *private = ntvfs->private_data; + + SETUP_PID; + + return smb_raw_search_next(private->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; + + SETUP_PID; + + return smb_raw_search_close(private->tree, io); +} + +/* + a handler for async trans2 replies + */ +static void async_trans2(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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); +} + +/* raw trans2 */ +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 smbcli_request *c_req; + + if (private->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); + } + + c_req = smb_raw_trans2_send(private->tree, trans2); + + ASYNC_RECV_TAIL(trans2, async_trans2); +} + + +/* SMBtrans - not used on file shares */ +static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + struct smb_trans2 *trans2) +{ + return NT_STATUS_ACCESS_DENIED; +} + +/* + a handler for async change notify replies + */ +static void async_changenotify(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + 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, + union smb_notify *io) +{ + struct cvfs_private *private = ntvfs->private_data; + struct smbcli_request *c_req; + int saved_timeout = private->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; + } + + /* we must not timeout on notify requests - they wait + forever */ + private->transport->options.request_timeout = 0; + + c_req = smb_raw_changenotify_send(private->tree, io); + + private->transport->options.request_timeout = saved_timeout; + + ASYNC_RECV_TAIL(io, async_changenotify); +} + +/* + initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem + */ +NTSTATUS ntvfs_smb2_init(void) +{ + NTSTATUS ret; + struct ntvfs_ops ops; + NTVFS_CURRENT_CRITICAL_SIZES(vers); + + ZERO_STRUCT(ops); + + /* fill in the name and type */ + ops.name = "smb2"; + ops.type = NTVFS_DISK; + + /* fill in all the operations */ + ops.connect = cvfs_connect; + ops.disconnect = cvfs_disconnect; + ops.unlink = cvfs_unlink; + ops.chkpath = cvfs_chkpath; + ops.qpathinfo = cvfs_qpathinfo; + ops.setpathinfo = cvfs_setpathinfo; + ops.open = cvfs_open; + ops.mkdir = cvfs_mkdir; + ops.rmdir = cvfs_rmdir; + ops.rename = cvfs_rename; + ops.copy = cvfs_copy; + ops.ioctl = cvfs_ioctl; + ops.read = cvfs_read; + ops.write = cvfs_write; + ops.seek = cvfs_seek; + ops.flush = cvfs_flush; + ops.close = cvfs_close; + ops.exit = cvfs_exit; + ops.lock = cvfs_lock; + ops.setfileinfo = cvfs_setfileinfo; + ops.qfileinfo = cvfs_qfileinfo; + ops.fsinfo = cvfs_fsinfo; + ops.lpq = cvfs_lpq; + ops.search_first = cvfs_search_first; + ops.search_next = cvfs_search_next; + ops.search_close = cvfs_search_close; + ops.trans = cvfs_trans; + ops.logoff = cvfs_logoff; + ops.async_setup = cvfs_async_setup; + ops.cancel = cvfs_cancel; + ops.notify = cvfs_notify; + ops.trans2 = cvfs_trans2; + + /* register ourselves with the NTVFS subsystem. We register + under the name 'smb2'. */ + ret = ntvfs_register(&ops, &vers); + + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register SMB2 backend\n")); + } + + return ret; +} -- cgit From 0abc2e2020f40d018587eb265f2a1467fdba4c89 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 15 May 2008 20:45:30 +1000 Subject: use a newer fsinfo level in smbclient, to support larger disks (This used to be commit 1acc8077fb86c1e78724b010d149db166d98238d) --- source4/client/client.c | 9 ++++++--- source4/libcli/clifile.c | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/source4/client/client.c b/source4/client/client.c index 120a80ccd2..01197e8a9e 100644 --- a/source4/client/client.c +++ b/source4/client/client.c @@ -214,15 +214,18 @@ check the space on a device ****************************************************************************/ static int do_dskattr(struct smbclient_context *ctx) { - int total, bsize, avail; + uint32_t bsize; + uint64_t total, avail; if (NT_STATUS_IS_ERR(smbcli_dskattr(ctx->cli->tree, &bsize, &total, &avail))) { d_printf("Error in dskattr: %s\n",smbcli_errstr(ctx->cli->tree)); return 1; } - d_printf("\n\t\t%d blocks of size %d. %d blocks available\n", - total, bsize, avail); + d_printf("\n\t\t%llu blocks of size %u. %llu blocks available\n", + (unsigned long long)total, + (unsigned)bsize, + (unsigned long long)avail); return 0; } diff --git a/source4/libcli/clifile.c b/source4/libcli/clifile.c index e59b7f9af3..2cf174060b 100644 --- a/source4/libcli/clifile.c +++ b/source4/libcli/clifile.c @@ -650,7 +650,8 @@ NTSTATUS smbcli_chkpath(struct smbcli_tree *tree, const char *path) /**************************************************************************** Query disk space. ****************************************************************************/ -NTSTATUS smbcli_dskattr(struct smbcli_tree *tree, int *bsize, int *total, int *avail) +NTSTATUS smbcli_dskattr(struct smbcli_tree *tree, uint32_t *bsize, + uint64_t *total, uint64_t *avail) { union smb_fsinfo fsinfo_parms; TALLOC_CTX *mem_ctx; @@ -658,12 +659,12 @@ NTSTATUS smbcli_dskattr(struct smbcli_tree *tree, int *bsize, int *total, int *a mem_ctx = talloc_init("smbcli_dskattr"); - fsinfo_parms.dskattr.level = RAW_QFS_DSKATTR; + fsinfo_parms.dskattr.level = RAW_QFS_SIZE_INFO; status = smb_raw_fsinfo(tree, mem_ctx, &fsinfo_parms); if (NT_STATUS_IS_OK(status)) { - *bsize = fsinfo_parms.dskattr.out.block_size; - *total = fsinfo_parms.dskattr.out.units_total; - *avail = fsinfo_parms.dskattr.out.units_free; + *bsize = fsinfo_parms.size_info.out.bytes_per_sector * fsinfo_parms.size_info.out.sectors_per_unit; + *total = fsinfo_parms.size_info.out.total_alloc_units; + *avail = fsinfo_parms.size_info.out.avail_alloc_units; } talloc_free(mem_ctx); -- cgit From 8846981807a08e86c19b585be135b738eb9edf61 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 15 May 2008 20:46:10 +1000 Subject: update some SMB2 find flags (This used to be commit b7560afd4bab984c0083e9687b69bc42970ad932) --- source4/libcli/raw/interfaces.h | 7 ++++--- source4/libcli/smb2/find.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h index bad3743721..871bab01db 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -2354,10 +2354,11 @@ union smb_search_first { #define SMB2_FIND_ID_BOTH_DIRECTORY_INFO 0x25 #define SMB2_FIND_ID_FULL_DIRECTORY_INFO 0x26 -/* flags for RAW_FILEINFO_SMB2_ALL_EAS */ +/* flags for SMB2 find */ #define SMB2_CONTINUE_FLAG_RESTART 0x01 #define SMB2_CONTINUE_FLAG_SINGLE 0x02 -#define SMB2_CONTINUE_FLAG_NEW 0x10 +#define SMB2_CONTINUE_FLAG_INDEX 0x04 +#define SMB2_CONTINUE_FLAG_REOPEN 0x10 /* SMB2 Find */ struct smb2_find { @@ -2370,7 +2371,7 @@ union smb_search_first { /* uint16_t buffer_code; 0x21 = 0x20 + 1 */ uint8_t level; uint8_t continue_flags; /* SMB2_CONTINUE_FLAG_* */ - uint32_t unknown; /* perhaps a continue token? */ + uint32_t file_index; /* struct smb2_handle handle; */ /* uint16_t pattern_ofs; */ /* uint16_t pattern_size; */ diff --git a/source4/libcli/smb2/find.c b/source4/libcli/smb2/find.c index 6b4902a026..8ebfd81bcd 100644 --- a/source4/libcli/smb2/find.c +++ b/source4/libcli/smb2/find.c @@ -38,7 +38,7 @@ struct smb2_request *smb2_find_send(struct smb2_tree *tree, struct smb2_find *io SCVAL(req->out.body, 0x02, io->in.level); SCVAL(req->out.body, 0x03, io->in.continue_flags); - SIVAL(req->out.body, 0x04, io->in.unknown); + SIVAL(req->out.body, 0x04, io->in.file_index); smb2_push_handle(req->out.body+0x08, &io->in.file.handle); status = smb2_push_o16s16_string(&req->out, 0x18, io->in.pattern); -- cgit From c0e247ab40a14ba11f021811a1bc160601bb59f7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 15 May 2008 20:46:43 +1000 Subject: better match WSPP doc name for find flags (This used to be commit 0e4b8602dec3ec87676c91a99371e5d77fe78196) --- source4/smb_server/smb2/find.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/smb_server/smb2/find.c b/source4/smb_server/smb2/find.c index 6018f1958f..f1b31d45ce 100644 --- a/source4/smb_server/smb2/find.c +++ b/source4/smb_server/smb2/find.c @@ -112,7 +112,7 @@ static NTSTATUS smb2srv_find_backend(struct smb2srv_find_state *state) return NT_STATUS_FOOBAR; } - if (info->in.continue_flags & SMB2_CONTINUE_FLAG_NEW) { + if (info->in.continue_flags & SMB2_CONTINUE_FLAG_REOPEN) { state->ff = talloc(state, union smb_search_first); NT_STATUS_HAVE_NO_MEMORY(state->ff); -- cgit From d9f47ba00b910ecbe031e635eeaf50b1c05a79cb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 15 May 2008 20:47:28 +1000 Subject: added handlers for connect, search_first and fsinfo. Directory listing in smbclient now works (This used to be commit 8007342061d77eb711af0652ecd38aec0d3cc9d1) --- source4/ntvfs/smb2/vfs_smb2.c | 377 +++++++++++++++++++++++++----------------- 1 file changed, 225 insertions(+), 152 deletions(-) diff --git a/source4/ntvfs/smb2/vfs_smb2.c b/source4/ntvfs/smb2/vfs_smb2.c index f253fcecaf..6b0f3e62f4 100644 --- a/source4/ntvfs/smb2/vfs_smb2.c +++ b/source4/ntvfs/smb2/vfs_smb2.c @@ -37,6 +37,8 @@ #include "lib/util/dlinklist.h" #include "param/param.h" #include "libcli/resolve/resolve.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" struct cvfs_file { struct cvfs_file *prev, *next; @@ -46,13 +48,17 @@ struct cvfs_file { /* this is stored in ntvfs_private */ struct cvfs_private { - struct smbcli_tree *tree; + struct smb2_tree *tree; struct smbcli_transport *transport; struct ntvfs_module_context *ntvfs; struct async_info *pending; struct cvfs_file *files; - bool map_generic; - bool map_trans2; + + /* a handle on the root of the share */ + /* TODO: leaving this handle open could prevent other users + from opening the share with exclusive access. We probably + need to open it on demand */ + struct smb2_handle roothandle; }; @@ -61,13 +67,11 @@ struct async_info { struct async_info *next, *prev; struct cvfs_private *cvfs; struct ntvfs_request *req; - struct smbcli_request *c_req; + struct smb2_request *c_req; struct cvfs_file *f; void *parms; }; -#define SETUP_PID private->tree->session->pid = req->smbpid - #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; \ @@ -79,23 +83,14 @@ struct async_info { SETUP_FILE_HERE(f); \ } while (0) -#define SETUP_PID_AND_FILE do { \ - SETUP_PID; \ - SETUP_FILE; \ -} while (0) +#define SMB2_SERVER "smb2:server" +#define SMB2_USER "smb2:user" +#define SMB2_PASSWORD "smb2:password" +#define SMB2_DOMAIN "smb2:domain" +#define SMB2_SHARE "smb2:share" +#define SMB2_USE_MACHINE_ACCT "smb2:use-machine-account" -#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_MAP_GENERIC "cifs:map-generic" -#define CIFS_MAP_TRANS2 "cifs:map-trans2" - -#define CIFS_USE_MACHINE_ACCT_DEFAULT false -#define CIFS_MAP_GENERIC_DEFAULT false -#define CIFS_MAP_TRANS2_DEFAULT true +#define SMB2_USE_MACHINE_ACCT_DEFAULT false /* a handler for oplock break events from the server - these need to be passed @@ -115,16 +110,44 @@ static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin } if (!h) { - DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level, fnum)); + DEBUG(5,("vfs_smb2: 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)); + DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level, fnum)); status = ntvfs_send_oplock_break(private->ntvfs, h, level); if (!NT_STATUS_IS_OK(status)) return false; return true; } +/* + return a handle to the root of the share +*/ +static NTSTATUS smb2_get_roothandle(struct smb2_tree *tree, struct smb2_handle *handle) +{ + struct smb2_create io; + NTSTATUS status; + + ZERO_STRUCT(io); + io.in.oplock_level = 0; + io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST; + io.in.file_attributes = 0; + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE; + io.in.create_options = 0; + io.in.fname = NULL; + + status = smb2_create(tree, tree, &io); + NT_STATUS_NOT_OK_RETURN(status); + + *handle = io.out.file.handle; + + return NT_STATUS_OK; +} + /* connect to a share - used when a tree_connect operation comes in. */ @@ -134,9 +157,9 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, NTSTATUS status; struct cvfs_private *private; const char *host, *user, *pass, *domain, *remote_share; - struct smb_composite_connect io; struct composite_context *creq; struct share_config *scfg = ntvfs->ctx->config; + struct smb2_tree *tree; struct cli_credentials *credentials; bool machine_account; @@ -145,16 +168,16 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, * For now we use parametric options, type cifs. * Later we will use security=server and auth_server.c. */ - 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); + host = share_string_option(scfg, SMB2_SERVER, NULL); + user = share_string_option(scfg, SMB2_USER, NULL); + pass = share_string_option(scfg, SMB2_PASSWORD, NULL); + domain = share_string_option(scfg, SMB2_DOMAIN, NULL); + remote_share = share_string_option(scfg, SMB2_SHARE, NULL); if (!remote_share) { remote_share = sharename; } - machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT); + machine_account = share_bool_option(scfg, SMB2_USE_MACHINE_ACCT, SMB2_USE_MACHINE_ACCT_DEFAULT); private = talloc_zero(ntvfs, struct cvfs_private); if (!private) { @@ -199,31 +222,19 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_PARAMETER; } - /* connect to the server, using the smbd event context */ - io.in.dest_host = host; - io.in.dest_ports = lp_smb_ports(ntvfs->ctx->lp_ctx); - io.in.called_name = host; - io.in.credentials = credentials; - io.in.fallback_to_anonymous = false; - io.in.workgroup = lp_workgroup(ntvfs->ctx->lp_ctx); - io.in.service = remote_share; - io.in.service_type = "?????"; - lp_smbcli_options(ntvfs->ctx->lp_ctx, &io.in.options); - - if (!(ntvfs->ctx->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS)) { - io.in.options.use_level2_oplocks = false; - } + creq = smb2_connect_send(private, host, remote_share, + lp_resolve_context(ntvfs->ctx->lp_ctx), + credentials, + ntvfs->ctx->event_ctx); - creq = smb_composite_connect_send(&io, private, - lp_resolve_context(ntvfs->ctx->lp_ctx), - ntvfs->ctx->event_ctx); - status = smb_composite_connect_recv(creq, private); + status = smb2_connect_recv(creq, private, &tree); NT_STATUS_NOT_OK_RETURN(status); - private->tree = io.out.tree; + status = smb2_get_roothandle(tree, &private->roothandle); + NT_STATUS_NOT_OK_RETURN(status); + private->tree = tree; private->transport = private->tree->session->transport; - SETUP_PID; private->ntvfs = ntvfs; ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); @@ -232,12 +243,9 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); /* we need to receive oplock break requests from the server */ + /* TODO: enable oplocks smbcli_oplock_handler(private->transport, oplock_handler, private); - - private->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT); - - private->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT); - + */ return NT_STATUS_OK; } @@ -252,7 +260,7 @@ static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs) /* first cleanup pending requests */ for (a=private->pending; a; a = an) { an = a->next; - smbcli_request_destroy(a->c_req); + smb2_request_destroy(a->c_req); talloc_free(a); } @@ -276,11 +284,13 @@ static int async_info_destructor(struct async_info *async) this handler can only be used for functions that don't return any parameters (those that just return a status code) */ -static void async_simple(struct smbcli_request *c_req) +static void async_simple(struct smb2_request *c_req) { struct async_info *async = c_req->async.private; struct ntvfs_request *req = async->req; - req->async_states->status = smbcli_request_simple_recv(c_req); + + smb2_request_receive(c_req); + req->async_states->status = smb2_request_destroy(c_req); talloc_free(async); req->async_states->send_fn(req); } @@ -321,8 +331,7 @@ static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - + return NT_STATUS_NOT_IMPLEMENTED; /* see if the front end will allow us to perform this function asynchronously. */ if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { @@ -355,7 +364,7 @@ static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID_AND_FILE; + SETUP_FILE; /* see if the front end will allow us to perform this function asynchronously. */ @@ -375,15 +384,31 @@ static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_chkpath *cp) { struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - - SETUP_PID; - + struct smb2_request *c_req; + struct smb2_find f; + + /* SMB2 doesn't have a chkpath operation, and also doesn't + have a query path info call, so the best seems to be to do a + find call, using the roothandle we established at connect + time */ + ZERO_STRUCT(f); + f.in.file.handle = private->roothandle; + f.in.level = SMB2_FIND_DIRECTORY_INFO; + f.in.pattern = cp->chkpath.in.path; + /* SMB2 find doesn't accept \ or the empty string - this is the best + approximation */ + if (strcmp(f.in.pattern, "\\") == 0 || + strcmp(f.in.pattern, "") == 0) { + f.in.pattern = "?"; + } + f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE | SMB2_CONTINUE_FLAG_RESTART; + f.in.max_response_size = 0x1000; + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_chkpath(private->tree, cp); + return smb2_find(private->tree, req, &f); } - c_req = smb_raw_chkpath_send(private->tree, cp); + c_req = smb2_find_send(private->tree, &f); SIMPLE_ASYNC_TAIL; } @@ -395,6 +420,7 @@ static void async_qpathinfo(struct smbcli_request *c_req) { struct async_info *async = c_req->async.private; struct ntvfs_request *req = async->req; + return NT_STATUS_NOT_IMPLEMENTED; req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms); talloc_free(async); req->async_states->send_fn(req); @@ -409,8 +435,6 @@ static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = 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); } @@ -427,6 +451,7 @@ static void async_qfileinfo(struct smbcli_request *c_req) { struct async_info *async = c_req->async.private; struct ntvfs_request *req = async->req; + return NT_STATUS_NOT_IMPLEMENTED; req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms); talloc_free(async); req->async_states->send_fn(req); @@ -441,7 +466,8 @@ static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID_AND_FILE; + return NT_STATUS_NOT_IMPLEMENTED; + SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_fileinfo(private->tree, req, io); @@ -462,8 +488,7 @@ static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - + return NT_STATUS_NOT_IMPLEMENTED; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_setpathinfo(private->tree, st); } @@ -511,10 +536,8 @@ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, struct cvfs_file *f; NTSTATUS status; - SETUP_PID; - - if (io->generic.level != RAW_OPEN_GENERIC && - private->map_generic) { + return NT_STATUS_NOT_IMPLEMENTED; + if (io->generic.level != RAW_OPEN_GENERIC) { return ntvfs_map_open(ntvfs, req, io); } @@ -556,8 +579,7 @@ static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - + return NT_STATUS_NOT_IMPLEMENTED; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_mkdir(private->tree, md); } @@ -576,8 +598,7 @@ static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - + return NT_STATUS_NOT_IMPLEMENTED; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_rmdir(private->tree, rd); } @@ -595,7 +616,7 @@ static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; + return NT_STATUS_NOT_IMPLEMENTED; if (ren->nttrans.level == RAW_RENAME_NTTRANS) { struct cvfs_file *f; @@ -643,10 +664,8 @@ static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - - if (io->generic.level != RAW_READ_GENERIC && - private->map_generic) { + return NT_STATUS_NOT_IMPLEMENTED; + if (io->generic.level != RAW_READ_GENERIC) { return ntvfs_map_read(ntvfs, req, io); } @@ -682,10 +701,8 @@ static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - - if (io->generic.level != RAW_WRITE_GENERIC && - private->map_generic) { + return NT_STATUS_NOT_IMPLEMENTED; + if (io->generic.level != RAW_WRITE_GENERIC) { return ntvfs_map_write(ntvfs, req, io); } SETUP_FILE; @@ -721,7 +738,8 @@ static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID_AND_FILE; + return NT_STATUS_NOT_IMPLEMENTED; + SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_seek(private->tree, io); @@ -742,7 +760,7 @@ static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; + return NT_STATUS_NOT_IMPLEMENTED; switch (io->generic.level) { case RAW_FLUSH_FLUSH: SETUP_FILE; @@ -773,10 +791,8 @@ static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, struct smbcli_request *c_req; struct cvfs_file *f; - SETUP_PID; - - if (io->generic.level != RAW_CLOSE_GENERIC && - private->map_generic) { + return NT_STATUS_NOT_IMPLEMENTED; + if (io->generic.level != RAW_CLOSE_GENERIC) { return ntvfs_map_close(ntvfs, req, io); } SETUP_FILE_HERE(f); @@ -804,8 +820,7 @@ static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - + return NT_STATUS_NOT_IMPLEMENTED; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_exit(private->tree->session); } @@ -844,6 +859,7 @@ static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct async_info *a; + return NT_STATUS_NOT_IMPLEMENTED; /* find the matching request */ for (a=private->pending;a;a=a->next) { if (a->req == req) { @@ -867,10 +883,8 @@ static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID; - - if (io->generic.level != RAW_LOCK_GENERIC && - private->map_generic) { + return NT_STATUS_NOT_IMPLEMENTED; + if (io->generic.level != RAW_LOCK_GENERIC) { return ntvfs_map_lock(ntvfs, req, io); } SETUP_FILE; @@ -893,7 +907,8 @@ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smbcli_request *c_req; - SETUP_PID_AND_FILE; + return NT_STATUS_NOT_IMPLEMENTED; + SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_setfileinfo(private->tree, io); @@ -907,11 +922,11 @@ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, /* a handler for async fsinfo replies */ -static void async_fsinfo(struct smbcli_request *c_req) +static void async_fsinfo(struct smb2_request *c_req) { struct async_info *async = c_req->async.private; struct ntvfs_request *req = async->req; - req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms); + req->async_states->status = smb2_getinfo_fs_recv(c_req, req, async->parms); talloc_free(async); req->async_states->send_fn(req); } @@ -923,15 +938,49 @@ static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fsinfo *fs) { struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; + struct smb2_request *c_req; + enum smb_fsinfo_level level = fs->generic.level; + + switch (level) { + /* some levels go straight through */ + case RAW_QFS_VOLUME_INFORMATION: + case RAW_QFS_SIZE_INFORMATION: + case RAW_QFS_DEVICE_INFORMATION: + case RAW_QFS_ATTRIBUTE_INFORMATION: + case RAW_QFS_QUOTA_INFORMATION: + case RAW_QFS_FULL_SIZE_INFORMATION: + case RAW_QFS_OBJECTID_INFORMATION: + break; - SETUP_PID; + /* some get mapped */ + case RAW_QFS_VOLUME_INFO: + level = RAW_QFS_VOLUME_INFORMATION; + break; + case RAW_QFS_SIZE_INFO: + level = RAW_QFS_SIZE_INFORMATION; + break; + case RAW_QFS_DEVICE_INFO: + level = RAW_QFS_DEVICE_INFORMATION; + break; + case RAW_QFS_ATTRIBUTE_INFO: + level = RAW_QFS_ATTRIBUTE_INFO; + break; + + default: + /* the rest get refused for now */ + DEBUG(0,("fsinfo level %u not possible on SMB2\n", + (unsigned)fs->generic.level)); + break; + } + + fs->generic.level = level; + fs->generic.handle = private->roothandle; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_fsinfo(private->tree, req, fs); + return smb2_getinfo_fs(private->tree, req, fs); } - c_req = smb_raw_fsinfo_send(private->tree, req, fs); + c_req = smb2_getinfo_fs_send(private->tree, fs); ASYNC_RECV_TAIL(fs, async_fsinfo); } @@ -954,10 +1003,72 @@ static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, bool (*callback)(void *, const union smb_search_data *)) { struct cvfs_private *private = ntvfs->private_data; + struct smb2_find f; + enum smb_search_data_level smb2_level; + uint32_t continue_flags = 0; + uint_t count, i; + union smb_search_data *data; + NTSTATUS status; + + if (io->generic.level != RAW_SEARCH_TRANS2) { + DEBUG(0,("We only support trans2 search in smb2 backend\n")); + return NT_STATUS_NOT_SUPPORTED; + } + + switch (io->generic.data_level) { + case RAW_SEARCH_DATA_DIRECTORY_INFO: + smb2_level = SMB2_FIND_DIRECTORY_INFO; + break; + case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: + smb2_level = SMB2_FIND_FULL_DIRECTORY_INFO; + break; + case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO: + smb2_level = SMB2_FIND_BOTH_DIRECTORY_INFO; + break; + case RAW_SEARCH_DATA_NAME_INFO: + smb2_level = SMB2_FIND_NAME_INFO; + break; + case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO: + smb2_level = SMB2_FIND_ID_FULL_DIRECTORY_INFO; + break; + case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: + smb2_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO; + break; + default: + DEBUG(0,("Unsupported search level %u for smb2 backend\n", + (unsigned)io->generic.data_level)); + return NT_STATUS_INVALID_INFO_CLASS; + } + + /* we do the search on the roothandle. This only works because + search is synchronous, otherwise we'd have no way to + distinguish multiple searches happening at once + */ + ZERO_STRUCT(f); + f.in.file.handle = private->roothandle; + f.in.level = smb2_level; + f.in.pattern = io->t2ffirst.in.pattern; + while (f.in.pattern[0] == '\\') { + f.in.pattern++; + } + f.in.continue_flags = 0; + f.in.max_response_size = 0x10000; + + status = smb2_find_level(private->tree, req, &f, &count, &data); + NT_STATUS_NOT_OK_RETURN(status); - SETUP_PID; + for (i=0;it2ffirst.out.handle = 0; + io->t2ffirst.out.count = i; + /* TODO: fix end_of_file */ + io->t2ffirst.out.end_of_search = 1; - return smb_raw_search_first(private->tree, req, io, search_private, callback); + talloc_free(data); + + return NT_STATUS_OK; } /* continue a search */ @@ -968,7 +1079,7 @@ static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, { struct cvfs_private *private = ntvfs->private_data; - SETUP_PID; + return NT_STATUS_NOT_IMPLEMENTED; return smb_raw_search_next(private->tree, req, io, search_private, callback); } @@ -979,47 +1090,11 @@ static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, { struct cvfs_private *private = ntvfs->private_data; - SETUP_PID; + return NT_STATUS_NOT_IMPLEMENTED; return smb_raw_search_close(private->tree, io); } -/* - a handler for async trans2 replies - */ -static void async_trans2(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - 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); -} - -/* raw trans2 */ -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 smbcli_request *c_req; - - if (private->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); - } - - c_req = smb_raw_trans2_send(private->tree, trans2); - - ASYNC_RECV_TAIL(trans2, async_trans2); -} - - /* SMBtrans - not used on file shares */ static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, @@ -1050,12 +1125,11 @@ static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs, int saved_timeout = private->transport->options.request_timeout; struct cvfs_file *f; + return NT_STATUS_NOT_IMPLEMENTED; 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; @@ -1123,7 +1197,6 @@ NTSTATUS ntvfs_smb2_init(void) ops.async_setup = cvfs_async_setup; ops.cancel = cvfs_cancel; ops.notify = cvfs_notify; - ops.trans2 = cvfs_trans2; /* register ourselves with the NTVFS subsystem. We register under the name 'smb2'. */ -- cgit From 2994b483c8e2f99eaf7b80744cb1375822e52a41 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 12:46:16 +1000 Subject: fixed file_index reference (This used to be commit edb4b38ed33b545d8024f45c602d3f5e4a74c511) --- source4/smb_server/smb2/find.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/smb_server/smb2/find.c b/source4/smb_server/smb2/find.c index f1b31d45ce..32b280c5c2 100644 --- a/source4/smb_server/smb2/find.c +++ b/source4/smb_server/smb2/find.c @@ -156,7 +156,7 @@ void smb2srv_find_recv(struct smb2srv_request *req) info->data_level = RAW_SEARCH_DATA_GENERIC;/* will be overwritten later */ info->in.level = CVAL(req->in.body, 0x02); info->in.continue_flags = CVAL(req->in.body, 0x03); - info->in.unknown = IVAL(req->in.body, 0x04); + info->in.file_index = IVAL(req->in.body, 0x04); info->in.file.ntvfs = smb2srv_pull_handle(req, req->in.body, 0x08); SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, info, req->in.body+0x18, &info->in.pattern)); info->in.max_response_size = IVAL(req->in.body, 0x1C); -- cgit From 94162b3222f0947c2122cabe9949d239f99bd530 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 12:46:28 +1000 Subject: fixed warning (This used to be commit d5165ed7a77120f42c25c4997be2630f0f1cb98c) --- source4/smb_server/smb/receive.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source4/smb_server/smb/receive.c b/source4/smb_server/smb/receive.c index 6cf33cf7c3..0afa3a652d 100644 --- a/source4/smb_server/smb/receive.c +++ b/source4/smb_server/smb/receive.c @@ -508,7 +508,8 @@ static void switch_message(int type, struct smbsrv_request *req) } } - DEBUG(5,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id.id)); + DEBUG(5,("switch message %s (task_id %u)\n", + smb_fn_name(type), (unsigned)req->smb_conn->connection->server_id.id)); /* this must be called before we do any reply */ if (flags & SIGNING_NO_REPLY) { -- cgit From 9b177f8d586830887282dc30e712bae0e9a06f33 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 15:01:31 +1000 Subject: added SMB2 proxying for unlink (This used to be commit a5459bd88092863668db199953458fe97162240c) --- source4/ntvfs/smb2/vfs_smb2.c | 470 ++++-------------------------------------- 1 file changed, 43 insertions(+), 427 deletions(-) diff --git a/source4/ntvfs/smb2/vfs_smb2.c b/source4/ntvfs/smb2/vfs_smb2.c index 6b0f3e62f4..13dbb4ea2e 100644 --- a/source4/ntvfs/smb2/vfs_smb2.c +++ b/source4/ntvfs/smb2/vfs_smb2.c @@ -30,6 +30,7 @@ #include "includes.h" #include "libcli/raw/libcliraw.h" #include "libcli/raw/raw_proto.h" +#include "libcli/composite/composite.h" #include "libcli/smb_composite/smb_composite.h" #include "auth/auth.h" #include "auth/credentials/credentials.h" @@ -49,7 +50,7 @@ struct cvfs_file { /* this is stored in ntvfs_private */ struct cvfs_private { struct smb2_tree *tree; - struct smbcli_transport *transport; + struct smb2_transport *transport; struct ntvfs_module_context *ntvfs; struct async_info *pending; struct cvfs_file *files; @@ -67,7 +68,8 @@ struct async_info { struct async_info *next, *prev; struct cvfs_private *cvfs; struct ntvfs_request *req; - struct smb2_request *c_req; + void *c_req; + struct composite_context *c_comp; struct cvfs_file *f; void *parms; }; @@ -260,7 +262,7 @@ static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs) /* first cleanup pending requests */ for (a=private->pending; a; a = an) { an = a->next; - smb2_request_destroy(a->c_req); + talloc_free(a->c_req); talloc_free(a); } @@ -280,13 +282,13 @@ static int async_info_destructor(struct async_info *async) } /* - a handler for simple async replies + a handler for simple async SMB2 replies this handler can only be used for functions that don't return any parameters (those that just return a status code) */ -static void async_simple(struct smb2_request *c_req) +static void async_simple_smb2(struct smb2_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; smb2_request_receive(c_req); @@ -295,6 +297,21 @@ static void async_simple(struct smb2_request *c_req) req->async_states->send_fn(req); } +/* + a handler for simple async composite replies + this handler can only be used for functions that don't return any + parameters (those that just return a status code) + */ +static void async_simple_composite(struct composite_context *c_req) +{ + struct async_info *async = c_req->async.private_data; + struct ntvfs_request *req = async->req; + + req->async_states->status = composite_wait_free(c_req); + talloc_free(async); + req->async_states->send_fn(req); +} + /* save some typing for the simple functions */ #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \ @@ -309,7 +326,7 @@ static void async_simple(struct smb2_request *c_req) async->cvfs = private; \ async->c_req = c_req; \ DLIST_ADD(private->pending, async); \ - c_req->async.private = async; \ + c_req->async.private_data = async; \ talloc_set_destructor(async, async_info_destructor); \ } \ c_req->async.fn = async_fn; \ @@ -319,7 +336,15 @@ static void async_simple(struct smb2_request *c_req) #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) +#define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2) +#define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite) + +#define CHECK_ASYNC(req) do { \ + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \ + DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \ + __location__)); \ + return NT_STATUS_NOT_IMPLEMENTED; \ + }} while (0) /* delete a file - the dirtype specifies the file types to include in the search. @@ -329,30 +354,13 @@ 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 smbcli_request *c_req; + struct composite_context *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - /* 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); - } + CHECK_ASYNC(req); - c_req = smb_raw_unlink_send(private->tree, unl); + c_req = smb2_composite_unlink_send(private->tree, unl); - SIMPLE_ASYNC_TAIL; -} - -/* - a handler for async ioctl replies - */ -static void async_ioctl(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - 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); + SIMPLE_COMPOSITE_TAIL; } /* @@ -361,20 +369,7 @@ static void async_ioctl(struct smbcli_request *c_req) static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_ioctl *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - - SETUP_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); - } - - c_req = smb_raw_ioctl_send(private->tree, io); - - ASYNC_RECV_TAIL(io, async_ioctl); + return NT_STATUS_NOT_IMPLEMENTED; } /* @@ -386,6 +381,8 @@ static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smb2_request *c_req; struct smb2_find f; + + CHECK_ASYNC(req); /* SMB2 doesn't have a chkpath operation, and also doesn't have a query path info call, so the best seems to be to do a @@ -404,57 +401,18 @@ static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE | SMB2_CONTINUE_FLAG_RESTART; f.in.max_response_size = 0x1000; - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb2_find(private->tree, req, &f); - } - c_req = smb2_find_send(private->tree, &f); SIMPLE_ASYNC_TAIL; } -/* - a handler for async qpathinfo replies - */ -static void async_qpathinfo(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - struct ntvfs_request *req = async->req; - return NT_STATUS_NOT_IMPLEMENTED; - req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms); - talloc_free(async); - req->async_states->send_fn(req); -} - /* return info on a pathname */ static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *info) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_pathinfo(private->tree, req, info); - } - - c_req = smb_raw_pathinfo_send(private->tree, info); - - ASYNC_RECV_TAIL(info, async_qpathinfo); -} - -/* - a handler for async qfileinfo replies - */ -static void async_qfileinfo(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - struct ntvfs_request *req = async->req; return NT_STATUS_NOT_IMPLEMENTED; - req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms); - talloc_free(async); - req->async_states->send_fn(req); } /* @@ -463,19 +421,7 @@ static void async_qfileinfo(struct smbcli_request *c_req) static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - SETUP_FILE; - - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_fileinfo(private->tree, req, io); - } - - c_req = smb_raw_fileinfo_send(private->tree, io); - - ASYNC_RECV_TAIL(io, async_qfileinfo); } @@ -485,89 +431,17 @@ static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_setfileinfo *st) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_setpathinfo(private->tree, st); - } - - c_req = smb_raw_setpathinfo_send(private->tree, st); - - SIMPLE_ASYNC_TAIL; } -/* - a handler for async open replies - */ -static void async_open(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - struct cvfs_private *cvfs = async->cvfs; - struct ntvfs_request *req = async->req; - 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); -} - /* open a file */ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_open *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - struct ntvfs_handle *h; - struct cvfs_file *f; - NTSTATUS status; - return NT_STATUS_NOT_IMPLEMENTED; - if (io->generic.level != RAW_OPEN_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)) { - union smb_handle *file; - - status = smb_raw_open(private->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, private->ntvfs, f); - NT_STATUS_NOT_OK_RETURN(status); - file->ntvfs = f->h; - DLIST_ADD(private->files, f); - - return NT_STATUS_OK; - } - - c_req = smb_raw_open_send(private->tree, io); - - ASYNC_RECV_TAIL_F(io, async_open, f); } /* @@ -576,17 +450,7 @@ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_mkdir *md) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_mkdir(private->tree, md); - } - - c_req = smb_raw_mkdir_send(private->tree, md); - - SIMPLE_ASYNC_TAIL; } /* @@ -595,16 +459,7 @@ static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, struct smb_rmdir *rd) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_rmdir(private->tree, rd); - } - c_req = smb_raw_rmdir_send(private->tree, rd); - - SIMPLE_ASYNC_TAIL; } /* @@ -613,25 +468,7 @@ static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_rename *ren) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - - 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); - } - - c_req = smb_raw_rename_send(private->tree, ren); - - SIMPLE_ASYNC_TAIL; } /* @@ -643,53 +480,13 @@ static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, return NT_STATUS_NOT_SUPPORTED; } -/* - a handler for async read replies - */ -static void async_read(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - 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); -} - /* read from a file */ static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_read *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (io->generic.level != RAW_READ_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, io); - } - - c_req = smb_raw_read_send(private->tree, io); - - ASYNC_RECV_TAIL(io, async_read); -} - -/* - a handler for async write replies - */ -static void async_write(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - 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); } /* @@ -698,34 +495,7 @@ static void async_write(struct smbcli_request *c_req) static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_write *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (io->generic.level != RAW_WRITE_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, io); - } - - c_req = smb_raw_write_send(private->tree, io); - - ASYNC_RECV_TAIL(io, async_write); -} - -/* - a handler for async seek replies - */ -static void async_seek(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - 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); } /* @@ -735,19 +505,7 @@ 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 smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - SETUP_FILE; - - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_seek(private->tree, io); - } - - c_req = smb_raw_seek_send(private->tree, io); - - ASYNC_RECV_TAIL(io, async_seek); } /* @@ -757,28 +515,7 @@ 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 smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - 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); - } - - c_req = smb_raw_flush_send(private->tree, io); - - SIMPLE_ASYNC_TAIL; } /* @@ -787,28 +524,7 @@ static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_close *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - struct cvfs_file *f; - return NT_STATUS_NOT_IMPLEMENTED; - if (io->generic.level != RAW_CLOSE_GENERIC) { - return ntvfs_map_close(ntvfs, req, io); - } - 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(private->files, f); - - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_close(private->tree, io); - } - - c_req = smb_raw_close_send(private->tree, io); - - SIMPLE_ASYNC_TAIL; } /* @@ -817,17 +533,7 @@ static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_exit(private->tree->session); - } - - c_req = smb_raw_exit_send(private->tree->session); - - SIMPLE_ASYNC_TAIL; } /* @@ -856,22 +562,7 @@ 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 async_info *a; - return NT_STATUS_NOT_IMPLEMENTED; - /* find the matching request */ - for (a=private->pending;a;a=a->next) { - if (a->req == req) { - break; - } - } - - if (a == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - return smb_raw_ntcancel(a->c_req); } /* @@ -880,21 +571,7 @@ static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_lock *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - if (io->generic.level != RAW_LOCK_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, io); - } - - c_req = smb_raw_lock_send(private->tree, io); - SIMPLE_ASYNC_TAIL; } /* @@ -904,18 +581,7 @@ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_setfileinfo *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - return NT_STATUS_NOT_IMPLEMENTED; - SETUP_FILE; - - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb_raw_setfileinfo(private->tree, io); - } - c_req = smb_raw_setfileinfo_send(private->tree, io); - - SIMPLE_ASYNC_TAIL; } @@ -924,7 +590,7 @@ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, */ static void async_fsinfo(struct smb2_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 = smb2_getinfo_fs_recv(c_req, req, async->parms); talloc_free(async); @@ -941,6 +607,8 @@ static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, struct smb2_request *c_req; enum smb_fsinfo_level level = fs->generic.level; + CHECK_ASYNC(req); + switch (level) { /* some levels go straight through */ case RAW_QFS_VOLUME_INFORMATION: @@ -976,10 +644,6 @@ static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, fs->generic.level = level; fs->generic.handle = private->roothandle; - if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - return smb2_getinfo_fs(private->tree, req, fs); - } - c_req = smb2_getinfo_fs_send(private->tree, fs); ASYNC_RECV_TAIL(fs, async_fsinfo); @@ -1005,7 +669,6 @@ static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, struct cvfs_private *private = ntvfs->private_data; struct smb2_find f; enum smb_search_data_level smb2_level; - uint32_t continue_flags = 0; uint_t count, i; union smb_search_data *data; NTSTATUS status; @@ -1077,22 +740,14 @@ static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, void *search_private, bool (*callback)(void *, const union smb_search_data *)) { - struct cvfs_private *private = ntvfs->private_data; - return NT_STATUS_NOT_IMPLEMENTED; - - return smb_raw_search_next(private->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; - return NT_STATUS_NOT_IMPLEMENTED; - - return smb_raw_search_close(private->tree, io); } /* SMBtrans - not used on file shares */ @@ -1103,51 +758,12 @@ static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, return NT_STATUS_ACCESS_DENIED; } -/* - a handler for async change notify replies - */ -static void async_changenotify(struct smbcli_request *c_req) -{ - struct async_info *async = c_req->async.private; - 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, union smb_notify *io) { - struct cvfs_private *private = ntvfs->private_data; - struct smbcli_request *c_req; - int saved_timeout = private->transport->options.request_timeout; - struct cvfs_file *f; - return NT_STATUS_NOT_IMPLEMENTED; - if (io->nttrans.level != RAW_NOTIFY_NTTRANS) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - 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; - } - - /* we must not timeout on notify requests - they wait - forever */ - private->transport->options.request_timeout = 0; - - c_req = smb_raw_changenotify_send(private->tree, io); - - private->transport->options.request_timeout = saved_timeout; - - ASYNC_RECV_TAIL(io, async_changenotify); } /* -- cgit From de99db1084c73007f1d6f66fe7efb7a1a9271dfc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 15:02:14 +1000 Subject: started adding SMB2 composite functions that emulate common SMB calls (such as unlink) (This used to be commit 433038f3fea60087bdca07dcc856d0be4a4753f3) --- source4/libcli/smb_composite/smb2.c | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 source4/libcli/smb_composite/smb2.c diff --git a/source4/libcli/smb_composite/smb2.c b/source4/libcli/smb_composite/smb2.c new file mode 100644 index 0000000000..7bce65fb27 --- /dev/null +++ b/source4/libcli/smb_composite/smb2.c @@ -0,0 +1,122 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2008 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . +*/ +/* + a composite API for making SMB-like calls using SMB2. This is useful + as SMB2 often requires more than one requests where a single SMB + request would do. In converting code that uses SMB to use SMB2, + these routines make life a lot easier +*/ + + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "libcli/composite/composite.h" +#include "libcli/smb_composite/smb_composite.h" +#include "param/param.h" +#include "libcli/smb2/smb2_calls.h" + +/* + continue after a SMB2 close + */ +static void continue_close(struct smb2_request *req) +{ + struct composite_context *ctx = talloc_get_type(req->async.private_data, + struct composite_context); + NTSTATUS status; + struct smb2_close close_parm; + + status = smb2_close_recv(req, &close_parm); + composite_error(ctx, status); +} + +/* + continue after the create in a composite unlink + */ +static void continue_unlink(struct smb2_request *req) +{ + struct composite_context *ctx = talloc_get_type(req->async.private_data, + struct composite_context); + struct smb2_tree *tree = req->tree; + struct smb2_create create_parm; + struct smb2_close close_parm; + NTSTATUS status; + + status = smb2_create_recv(req, ctx, &create_parm); + if (!NT_STATUS_IS_OK(status)) { + composite_error(ctx, status); + return; + } + + ZERO_STRUCT(close_parm); + close_parm.in.file.handle = create_parm.out.file.handle; + + req = smb2_close_send(tree, &close_parm); + composite_continue_smb2(ctx, req, continue_close, ctx); +} + +/* + composite SMB2 unlink call +*/ +struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree, + union smb_unlink *io) +{ + struct composite_context *ctx; + struct smb2_create create_parm; + struct smb2_request *req; + + ctx = composite_create(tree, tree->session->transport->socket->event.ctx); + if (ctx == NULL) return NULL; + + /* check for wildcards - we could support these with a + search, but for now they aren't necessary */ + if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) { + composite_error(ctx, NT_STATUS_NOT_SUPPORTED); + return ctx; + } + + ZERO_STRUCT(create_parm); + create_parm.in.desired_access = SEC_STD_DELETE; + create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; + create_parm.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create_parm.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + create_parm.in.fname = io->unlink.in.pattern; + if (create_parm.in.fname[0] == '\\') { + create_parm.in.fname++; + } + + req = smb2_create_send(tree, &create_parm); + + composite_continue_smb2(ctx, req, continue_unlink, ctx); + return ctx; +} + + +/* + composite unlink call - sync interface +*/ +NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io) +{ + struct composite_context *c = smb2_composite_unlink_send(tree, io); + return composite_wait_free(c); +} + -- cgit From 14ca2b5b5db4abb1e6ab624365fdebfd9ec422e0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 15:02:58 +1000 Subject: - added a composite_wait_free() call - allow composite_error() to take NT_STATUS_OK (This used to be commit 5240e1e25655af1f9b92da99e85d845bf30c4e9e) --- source4/libcli/composite/composite.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/source4/libcli/composite/composite.c b/source4/libcli/composite/composite.c index 966f56cba8..3e3f224f47 100644 --- a/source4/libcli/composite/composite.c +++ b/source4/libcli/composite/composite.c @@ -69,6 +69,17 @@ _PUBLIC_ NTSTATUS composite_wait(struct composite_context *c) return c->status; } +/* + block until a composite function has completed, then return the status. + Free the composite context before returning +*/ +_PUBLIC_ NTSTATUS composite_wait_free(struct composite_context *c) +{ + NTSTATUS status = composite_wait(c); + talloc_free(c); + return status; +} + /* callback from composite_done() and composite_error() @@ -94,6 +105,12 @@ static void composite_trigger(struct event_context *ev, struct timed_event *te, _PUBLIC_ void composite_error(struct composite_context *ctx, NTSTATUS status) { + /* you are allowed to pass NT_STATUS_OK to composite_error(), in which + case it is equivalent to composite_done() */ + if (NT_STATUS_IS_OK(status)) { + composite_done(ctx); + return; + } if (!ctx->used_wait && !ctx->async.fn) { event_add_timed(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx); } @@ -187,7 +204,7 @@ _PUBLIC_ void composite_continue_smb2(struct composite_context *ctx, { if (composite_nomem(new_req, ctx)) return; new_req->async.fn = continuation; - new_req->async.private = private_data; + new_req->async.private_data = private_data; } _PUBLIC_ void composite_continue_nbt(struct composite_context *ctx, -- cgit From c02b0f47a0c85250715a1c511415a6cb4fe7a082 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 15:03:12 +1000 Subject: declare composite_wait_free() (This used to be commit 5b6f80aba30fc8ade26f73b0a1336c22e40b66a9) --- source4/libcli/composite/composite.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source4/libcli/composite/composite.h b/source4/libcli/composite/composite.h index f1bed20361..28cd6a88dc 100644 --- a/source4/libcli/composite/composite.h +++ b/source4/libcli/composite/composite.h @@ -101,6 +101,7 @@ bool composite_is_ok(struct composite_context *ctx); void composite_done(struct composite_context *ctx); void composite_error(struct composite_context *ctx, NTSTATUS status); NTSTATUS composite_wait(struct composite_context *c); +NTSTATUS composite_wait_free(struct composite_context *c); #endif /* __COMPOSITE_H__ */ -- cgit From 9bfafcfc213477a4f117ab07ce8f37bc18e74293 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 15:03:24 +1000 Subject: build the smb2 composite calls (This used to be commit ac10e3ad15dd17b96424987d1a2b7a0e4dc67cd0) --- source4/libcli/config.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index 95b45003be..4350cd7b04 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -33,7 +33,8 @@ LIBCLI_SMB_COMPOSITE_OBJ_FILES = $(addprefix libcli/smb_composite/, \ sesssetup.o \ fetchfile.o \ appendacl.o \ - fsinfo.o) + fsinfo.o \ + smb2.o) [SUBSYSTEM::NDR_NBT_BUF] -- cgit From c7d7577fb978dfa822b4aab238440816188099c6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 16 May 2008 15:03:58 +1000 Subject: private -> private_data for struct smb2_request (This used to be commit 67290e0ad69df2f2fe651249c6550b8e32dd641b) --- source4/libcli/smb2/connect.c | 8 ++++---- source4/libcli/smb2/request.c | 25 +++++++++++++++++-------- source4/libcli/smb2/session.c | 4 ++-- source4/libcli/smb2/smb2.h | 7 ++++++- source4/libcli/smb_composite/smb_composite.h | 1 + source4/librpc/rpc/dcerpc_smb2.c | 16 ++++++++-------- source4/torture/smb2/oplocks.c | 2 +- 7 files changed, 39 insertions(+), 24 deletions(-) diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index 59d4e6ea2d..867af14c92 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -44,7 +44,7 @@ struct smb2_connect_state { */ static void continue_tcon(struct smb2_request *req) { - struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context *c = talloc_get_type(req->async.private_data, struct composite_context); struct smb2_connect_state *state = talloc_get_type(c->private_data, struct smb2_connect_state); @@ -83,7 +83,7 @@ static void continue_session(struct composite_context *creq) if (composite_nomem(req, c)) return; req->async.fn = continue_tcon; - req->async.private = c; + req->async.private_data = c; } /* @@ -91,7 +91,7 @@ static void continue_session(struct composite_context *creq) */ static void continue_negprot(struct smb2_request *req) { - struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context *c = talloc_get_type(req->async.private_data, struct composite_context); struct smb2_connect_state *state = talloc_get_type(c->private_data, struct smb2_connect_state); @@ -142,7 +142,7 @@ static void continue_socket(struct composite_context *creq) if (composite_nomem(req, c)) return; req->async.fn = continue_negprot; - req->async.private = c; + req->async.private_data = c; } diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index f52b0ceef2..64d427f889 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -43,6 +43,18 @@ void smb2_setup_bufinfo(struct smb2_request *req) } } + +/* destroy a request structure */ +static int smb2_request_destructor(struct smb2_request *req) +{ + if (req->transport) { + /* remove it from the list of pending requests (a null op if + its not in the list) */ + DLIST_REMOVE(req->transport->pending_recv, req); + } + return 0; +} + /* initialise a smb2 request */ @@ -122,6 +134,8 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_ SCVAL(req->out.dynamic, 0, 0); } + talloc_set_destructor(req, smb2_request_destructor); + return req; } @@ -154,18 +168,13 @@ NTSTATUS smb2_request_destroy(struct smb2_request *req) _send() call fails completely */ if (!req) return NT_STATUS_UNSUCCESSFUL; - if (req->transport) { - /* remove it from the list of pending requests (a null op if - its not in the list) */ - DLIST_REMOVE(req->transport->pending_recv, req); - } - if (req->state == SMB2_REQUEST_ERROR && NT_STATUS_IS_OK(req->status)) { - req->status = NT_STATUS_INTERNAL_ERROR; + status = NT_STATUS_INTERNAL_ERROR; + } else { + status = req->status; } - status = req->status; talloc_free(req); return status; } diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c index 18fe3486a4..29af6652f2 100644 --- a/source4/libcli/smb2/session.c +++ b/source4/libcli/smb2/session.c @@ -145,7 +145,7 @@ struct smb2_session_state { */ static void session_request_handler(struct smb2_request *req) { - struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context *c = talloc_get_type(req->async.private_data, struct composite_context); struct smb2_session_state *state = talloc_get_type(c->private_data, struct smb2_session_state); @@ -178,7 +178,7 @@ static void session_request_handler(struct smb2_request *req) } state->req->async.fn = session_request_handler; - state->req->async.private = c; + state->req->async.private_data = c; return; } diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index ae66a6e0d3..964dcf320c 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -19,6 +19,9 @@ along with this program. If not, see . */ +#ifndef __LIBCLI_SMB2_SMB2_H__ +#define __LIBCLI_SMB2_SMB2_H__ + #include "libcli/raw/request.h" struct smb2_handle; @@ -165,7 +168,7 @@ struct smb2_request { */ struct { void (*fn)(struct smb2_request *); - void *private; + void *private_data; } async; }; @@ -282,3 +285,5 @@ struct smb2_request { return NT_STATUS_INVALID_PARAMETER; \ } \ } while (0) + +#endif diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h index afee11ce3b..7f4b9d73e4 100644 --- a/source4/libcli/smb_composite/smb_composite.h +++ b/source4/libcli/smb_composite/smb_composite.h @@ -29,6 +29,7 @@ #include "libcli/raw/signing.h" #include "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" /* diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c index 8adca4caba..4767165fba 100644 --- a/source4/librpc/rpc/dcerpc_smb2.c +++ b/source4/librpc/rpc/dcerpc_smb2.c @@ -83,7 +83,7 @@ static void smb2_read_callback(struct smb2_request *req) uint16_t frag_length; NTSTATUS status; - state = talloc_get_type(req->async.private, struct smb2_read_state); + state = talloc_get_type(req->async.private_data, struct smb2_read_state); smb = talloc_get_type(state->c->transport.private_data, struct smb2_private); status = smb2_read_recv(req, state, &io); @@ -136,7 +136,7 @@ static void smb2_read_callback(struct smb2_request *req) } req->async.fn = smb2_read_callback; - req->async.private = state; + req->async.private_data = state; } @@ -180,7 +180,7 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO } req->async.fn = smb2_read_callback; - req->async.private = state; + req->async.private_data = state; return NT_STATUS_OK; } @@ -212,7 +212,7 @@ struct smb2_trans_state { */ static void smb2_trans_callback(struct smb2_request *req) { - struct smb2_trans_state *state = talloc_get_type(req->async.private, + struct smb2_trans_state *state = talloc_get_type(req->async.private_data, struct smb2_trans_state); struct dcerpc_connection *c = state->c; NTSTATUS status; @@ -269,7 +269,7 @@ static NTSTATUS smb2_send_trans_request(struct dcerpc_connection *c, DATA_BLOB * } req->async.fn = smb2_trans_callback; - req->async.private = state; + req->async.private_data = state; talloc_steal(state, req); @@ -281,7 +281,7 @@ static NTSTATUS smb2_send_trans_request(struct dcerpc_connection *c, DATA_BLOB * */ static void smb2_write_callback(struct smb2_request *req) { - struct dcerpc_connection *c = (struct dcerpc_connection *)req->async.private; + struct dcerpc_connection *c = (struct dcerpc_connection *)req->async.private_data; if (!NT_STATUS_IS_OK(req->status)) { DEBUG(0,("dcerpc_smb2: write callback error\n")); @@ -319,7 +319,7 @@ static NTSTATUS smb2_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, } req->async.fn = smb2_write_callback; - req->async.private = c; + req->async.private_data = c; return NT_STATUS_OK; } @@ -444,7 +444,7 @@ struct composite_context *dcerpc_pipe_open_smb2_send(struct dcerpc_pipe *p, static void pipe_open_recv(struct smb2_request *req) { struct pipe_open_smb2_state *state = - talloc_get_type(req->async.private, + talloc_get_type(req->async.private_data, struct pipe_open_smb2_state); struct composite_context *ctx = state->ctx; struct dcerpc_connection *c = state->c; diff --git a/source4/torture/smb2/oplocks.c b/source4/torture/smb2/oplocks.c index b0a1b31d1f..9a06ae1f19 100644 --- a/source4/torture/smb2/oplocks.c +++ b/source4/torture/smb2/oplocks.c @@ -99,7 +99,7 @@ static bool torture_oplock_handler(struct smb2_transport *transport, req = smb2_break_send(tree, &break_info.br); req->async.fn = torture_oplock_break_callback; - req->async.private = NULL; + req->async.private_data = NULL; return true; } -- cgit From 66cbf7eb59ab4a29dca1d30850c9aeb35a598b3d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 19 May 2008 11:39:16 +1000 Subject: added mkdir to SMB2 proxy (This used to be commit 1323aab11fbf346e19c4cef227d727ddfcaa7d60) --- source4/libcli/smb_composite/smb2.c | 72 +++++++++++++++++++++++++++++++++++++ source4/ntvfs/smb2/vfs_smb2.c | 9 ++++- source4/torture/smb2/util.c | 24 +++---------- 3 files changed, 85 insertions(+), 20 deletions(-) diff --git a/source4/libcli/smb_composite/smb2.c b/source4/libcli/smb_composite/smb2.c index 7bce65fb27..7fccbe3a3c 100644 --- a/source4/libcli/smb_composite/smb2.c +++ b/source4/libcli/smb_composite/smb2.c @@ -120,3 +120,75 @@ NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io) return composite_wait_free(c); } + + + +/* + continue after the create in a composite mkdir + */ +static void continue_mkdir(struct smb2_request *req) +{ + struct composite_context *ctx = talloc_get_type(req->async.private_data, + struct composite_context); + struct smb2_tree *tree = req->tree; + struct smb2_create create_parm; + struct smb2_close close_parm; + NTSTATUS status; + + status = smb2_create_recv(req, ctx, &create_parm); + if (!NT_STATUS_IS_OK(status)) { + composite_error(ctx, status); + return; + } + + ZERO_STRUCT(close_parm); + close_parm.in.file.handle = create_parm.out.file.handle; + + req = smb2_close_send(tree, &close_parm); + composite_continue_smb2(ctx, req, continue_close, ctx); +} + +/* + composite SMB2 mkdir call +*/ +struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree, + union smb_mkdir *io) +{ + struct composite_context *ctx; + struct smb2_create create_parm; + struct smb2_request *req; + + ctx = composite_create(tree, tree->session->transport->socket->event.ctx); + if (ctx == NULL) return NULL; + + ZERO_STRUCT(create_parm); + + create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; + create_parm.in.share_access = + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + create_parm.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + create_parm.in.create_disposition = NTCREATEX_DISP_CREATE; + create_parm.in.fname = io->mkdir.in.path; + if (create_parm.in.fname[0] == '\\') { + create_parm.in.fname++; + } + + req = smb2_create_send(tree, &create_parm); + + composite_continue_smb2(ctx, req, continue_mkdir, ctx); + + return ctx; +} + + +/* + composite mkdir call - sync interface +*/ +NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io) +{ + struct composite_context *c = smb2_composite_mkdir_send(tree, io); + return composite_wait_free(c); +} + diff --git a/source4/ntvfs/smb2/vfs_smb2.c b/source4/ntvfs/smb2/vfs_smb2.c index 13dbb4ea2e..3a9a74a928 100644 --- a/source4/ntvfs/smb2/vfs_smb2.c +++ b/source4/ntvfs/smb2/vfs_smb2.c @@ -450,7 +450,14 @@ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_mkdir *md) { - return NT_STATUS_NOT_IMPLEMENTED; + struct cvfs_private *private = ntvfs->private_data; + struct composite_context *c_req; + + CHECK_ASYNC(req); + + c_req = smb2_composite_mkdir_send(private->tree, md); + + SIMPLE_COMPOSITE_TAIL; } /* diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c index 6ac3926c98..4995bbe978 100644 --- a/source4/torture/smb2/util.c +++ b/source4/torture/smb2/util.c @@ -22,6 +22,7 @@ #include "includes.h" #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" +#include "libcli/smb_composite/smb_composite.h" #include "lib/cmdline/popt_common.h" #include "lib/events/events.h" #include "system/time.h" @@ -51,27 +52,12 @@ NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h) */ NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname) { - struct smb2_create io; - NTSTATUS status; - + union smb_unlink io; + ZERO_STRUCT(io); - io.in.desired_access = SEC_RIGHTS_FILE_ALL; - io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; - io.in.create_disposition = NTCREATEX_DISP_OPEN; - io.in.share_access = - NTCREATEX_SHARE_ACCESS_DELETE| - NTCREATEX_SHARE_ACCESS_READ| - NTCREATEX_SHARE_ACCESS_WRITE; - io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; - io.in.fname = fname; - - status = smb2_create(tree, tree, &io); - if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - return NT_STATUS_OK; - } - NT_STATUS_NOT_OK_RETURN(status); + io.unlink.in.pattern = fname; - return smb2_util_close(tree, io.out.file.handle); + return smb2_composite_unlink(tree, &io); } /* -- cgit From e7d993b8b26e121ff37640825b4d2f2c4d6332bf Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 19 May 2008 13:05:08 +1000 Subject: added SMB2 proxying of rmdir (This used to be commit 1e0c24b2760f2a632333b51710cd9581f0cee851) --- source4/libcli/smb_composite/smb2.c | 74 ++++++++++++++++++++++++++++++++++++- source4/ntvfs/smb2/vfs_smb2.c | 13 ++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/source4/libcli/smb_composite/smb2.c b/source4/libcli/smb_composite/smb2.c index 7fccbe3a3c..84b4f66b61 100644 --- a/source4/libcli/smb_composite/smb2.c +++ b/source4/libcli/smb_composite/smb2.c @@ -98,7 +98,9 @@ struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree, NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; - create_parm.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + create_parm.in.create_options = + NTCREATEX_OPTIONS_DELETE_ON_CLOSE | + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; create_parm.in.fname = io->unlink.in.pattern; if (create_parm.in.fname[0] == '\\') { create_parm.in.fname++; @@ -192,3 +194,73 @@ NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io) return composite_wait_free(c); } + + +/* + continue after the create in a composite rmdir + */ +static void continue_rmdir(struct smb2_request *req) +{ + struct composite_context *ctx = talloc_get_type(req->async.private_data, + struct composite_context); + struct smb2_tree *tree = req->tree; + struct smb2_create create_parm; + struct smb2_close close_parm; + NTSTATUS status; + + status = smb2_create_recv(req, ctx, &create_parm); + if (!NT_STATUS_IS_OK(status)) { + composite_error(ctx, status); + return; + } + + ZERO_STRUCT(close_parm); + close_parm.in.file.handle = create_parm.out.file.handle; + + req = smb2_close_send(tree, &close_parm); + composite_continue_smb2(ctx, req, continue_close, ctx); +} + +/* + composite SMB2 rmdir call +*/ +struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree, + struct smb_rmdir *io) +{ + struct composite_context *ctx; + struct smb2_create create_parm; + struct smb2_request *req; + + ctx = composite_create(tree, tree->session->transport->socket->event.ctx); + if (ctx == NULL) return NULL; + + ZERO_STRUCT(create_parm); + create_parm.in.desired_access = SEC_STD_DELETE; + create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; + create_parm.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create_parm.in.create_options = + NTCREATEX_OPTIONS_DIRECTORY | + NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + create_parm.in.fname = io->in.path; + if (create_parm.in.fname[0] == '\\') { + create_parm.in.fname++; + } + + req = smb2_create_send(tree, &create_parm); + + composite_continue_smb2(ctx, req, continue_rmdir, ctx); + return ctx; +} + + +/* + composite rmdir call - sync interface +*/ +NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io) +{ + struct composite_context *c = smb2_composite_rmdir_send(tree, io); + return composite_wait_free(c); +} diff --git a/source4/ntvfs/smb2/vfs_smb2.c b/source4/ntvfs/smb2/vfs_smb2.c index 3a9a74a928..cc09daf83f 100644 --- a/source4/ntvfs/smb2/vfs_smb2.c +++ b/source4/ntvfs/smb2/vfs_smb2.c @@ -349,6 +349,10 @@ static void async_simple_composite(struct composite_context *c_req) /* delete a file - the dirtype specifies the file types to include in the search. The name can contain CIFS wildcards, but rarely does (except with OS/2 clients) + + BUGS: + - doesn't handle wildcards + - doesn't obey attrib restrictions */ static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_unlink *unl) @@ -466,7 +470,14 @@ static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, struct smb_rmdir *rd) { - return NT_STATUS_NOT_IMPLEMENTED; + struct cvfs_private *private = ntvfs->private_data; + struct composite_context *c_req; + + CHECK_ASYNC(req); + + c_req = smb2_composite_rmdir_send(private->tree, rd); + + SIMPLE_COMPOSITE_TAIL; } /* -- cgit From 9c6a35ad9ba9458fe9d3a73ba1f785a61305e2aa Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 11:57:43 +1000 Subject: remember the server time fields on negotiate. Needed for gentest (This used to be commit 7989ca861dcc700b52be3a47ea5ae8b03fbb9330) --- source4/libcli/smb2/connect.c | 3 +++ source4/libcli/smb2/smb2.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index 867af14c92..eabfa410ad 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -101,6 +101,9 @@ static void continue_negprot(struct smb2_request *req) c->status = smb2_negprot_recv(req, c, &state->negprot); if (!composite_is_ok(c)) return; + transport->negotiate.system_time = state->negprot.out.system_time; + transport->negotiate.server_start_time = state->negprot.out.server_start_time; + state->session = smb2_session_init(transport, global_loadparm, state, true); if (composite_nomem(state->session, c)) return; diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index 964dcf320c..b55da05e21 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -35,6 +35,8 @@ struct smb2_options { */ struct smb2_negotiate { DATA_BLOB secblob; + NTTIME system_time; + NTTIME server_start_time; }; /* this is the context for the smb2 transport layer */ -- cgit From 803c076450da4075c71faaba3f0882f0b8e6208a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 11:58:04 +1000 Subject: added some SMB2 utility functions (This used to be commit 6a3b1cd6698faa460c6258bb41b4936e363f4387) --- source4/libcli/smb2/config.mk | 2 +- source4/libcli/smb2/util.c | 178 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 source4/libcli/smb2/util.c diff --git a/source4/libcli/smb2/config.mk b/source4/libcli/smb2/config.mk index e653fbac1c..00b6305def 100644 --- a/source4/libcli/smb2/config.mk +++ b/source4/libcli/smb2/config.mk @@ -5,6 +5,6 @@ LIBCLI_SMB2_OBJ_FILES = $(addprefix $(libclisrcdir)/smb2/, \ transport.o request.o negprot.o session.o tcon.o \ create.o close.o connect.o getinfo.o write.o read.o \ setinfo.o find.o ioctl.o logoff.o tdis.o flush.o \ - lock.o notify.o cancel.o keepalive.o break.o) + lock.o notify.o cancel.o keepalive.o break.o util.o) $(eval $(call proto_header_template,$(libclisrcdir)/smb2/smb2_proto.h,$(LIBCLI_SMB2_OBJ_FILES:.o=.c))) diff --git a/source4/libcli/smb2/util.c b/source4/libcli/smb2/util.c new file mode 100644 index 0000000000..0fc03b48c5 --- /dev/null +++ b/source4/libcli/smb2/util.c @@ -0,0 +1,178 @@ +/* + Unix SMB/CIFS implementation. + + SMB2 client utility functions + + Copyright (C) Andrew Tridgell 2005 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "libcli/smb_composite/smb_composite.h" + +/* + simple close wrapper with SMB2 +*/ +NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h) +{ + struct smb2_close c; + + ZERO_STRUCT(c); + c.in.file.handle = h; + + return smb2_close(tree, &c); +} + +/* + unlink a file with SMB2 +*/ +NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname) +{ + union smb_unlink io; + + ZERO_STRUCT(io); + io.unlink.in.pattern = fname; + + return smb2_composite_unlink(tree, &io); +} + + +/* + rmdir with SMB2 +*/ +NTSTATUS smb2_util_rmdir(struct smb2_tree *tree, const char *dname) +{ + struct smb_rmdir io; + + ZERO_STRUCT(io); + io.in.path = dname; + + return smb2_composite_rmdir(tree, &io); +} + + +/* + mkdir with SMB2 +*/ +NTSTATUS smb2_util_mkdir(struct smb2_tree *tree, const char *dname) +{ + union smb_mkdir io; + + ZERO_STRUCT(io); + io.mkdir.level = RAW_MKDIR_MKDIR; + io.mkdir.in.path = dname; + + return smb2_composite_mkdir(tree, &io); +} + + + + +/* + recursively descend a tree deleting all files + returns the number of files deleted, or -1 on error +*/ +int smb2_deltree(struct smb2_tree *tree, const char *dname) +{ + NTSTATUS status; + uint32_t total_deleted = 0; + uint_t count, i; + union smb_search_data *list; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + struct smb2_find f; + struct smb2_create create_parm; + + /* it might be a file */ + status = smb2_util_unlink(tree, dname); + if (NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return 1; + } + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) || + NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) || + NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) { + talloc_free(tmp_ctx); + return 0; + } + + ZERO_STRUCT(create_parm); + create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; + create_parm.in.share_access = + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; + create_parm.in.fname = dname; + + status = smb2_create(tree, tmp_ctx, &create_parm); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(2,("Failed to open %s - %s\n", dname, nt_errstr(status))); + talloc_free(tmp_ctx); + return -1; + } + + + ZERO_STRUCT(f); + f.in.file.handle = create_parm.out.file.handle; + f.in.max_response_size = 0x10000; + f.in.level = SMB2_FIND_NAME_INFO; + f.in.pattern = "*"; + + status = smb2_find_level(tree, tmp_ctx, &f, &count, &list); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(2,("Failed to list %s - %s\n", + dname, nt_errstr(status))); + smb2_util_close(tree, create_parm.out.file.handle); + talloc_free(tmp_ctx); + return -1; + } + + for (i=0;i 0) total_deleted += ret; + } + talloc_free(name); + if (NT_STATUS_IS_OK(status)) { + total_deleted++; + } + } + + smb2_util_close(tree, create_parm.out.file.handle); + + status = smb2_util_rmdir(tree, dname); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(2,("Failed to delete %s - %s\n", + dname, nt_errstr(status))); + talloc_free(tmp_ctx); + return -1; + } + + talloc_free(tmp_ctx); + + return total_deleted; +} -- cgit From 2352602a57989ac1572151cba1da1e78b9410860 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 11:58:47 +1000 Subject: check the creation options where the client can require a path to be a file or a directory (This used to be commit c05b58940f06b01b9770c218eb0708cb621215ef) --- source4/ntvfs/posix/pvfs_open.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index c9c1c56f14..67937324cc 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -1117,6 +1117,20 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, return status; } + /* if the client specified that it must not be a directory then + check that it isn't */ + if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) && + (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + /* if the client specified that it must be a directory then + check that it is */ + if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) && + (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) { + return NT_STATUS_NOT_A_DIRECTORY; + } + /* directory opens are handled separately */ if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) || (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) { -- cgit From f8f0cc985b181d5d19703fa3d16ec3de876fe4a8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 11:59:18 +1000 Subject: moved these util functions into libcli (This used to be commit b2f1154bc338fb56fc998f40159156cb6859075b) --- source4/torture/smb2/util.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c index 4995bbe978..af4f345104 100644 --- a/source4/torture/smb2/util.c +++ b/source4/torture/smb2/util.c @@ -34,32 +34,6 @@ #include "torture/smb2/proto.h" -/* - close a handle with SMB2 -*/ -NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h) -{ - struct smb2_close c; - - ZERO_STRUCT(c); - c.in.file.handle = h; - - return smb2_close(tree, &c); -} - -/* - unlink a file with SMB2 -*/ -NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname) -{ - union smb_unlink io; - - ZERO_STRUCT(io); - io.unlink.in.pattern = fname; - - return smb2_composite_unlink(tree, &io); -} - /* write to a file on SMB2 */ -- cgit From fc267b0510c6a1a46c57bacce8490491f623a42c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 11:59:43 +1000 Subject: first version of gentest_smb2. Only generates create and close so far. (This used to be commit 634a4bbd98e1c281f8339073b90cb7696ac59baa) --- source4/torture/config.mk | 17 + source4/torture/gentest_smb2.c | 1966 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1983 insertions(+) create mode 100644 source4/torture/gentest_smb2.c diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 5fde227031..e82cb4523d 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -261,6 +261,23 @@ gentest_OBJ_FILES = $(torturesrcdir)/gentest.o MANPAGES += $(torturesrcdir)/man/gentest.1 +################################# +# Start BINARY gentest_smb2 +[BINARY::gentest_smb2] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + LIBPOPT \ + POPT_SAMBA \ + POPT_CREDENTIALS \ + LIBCLI_SMB \ + LIBCLI_RAW +# End BINARY gentest_smb2 +################################# + +gentest_smb2_OBJ_FILES = $(torturesrcdir)/gentest_smb2.o + ################################# # Start BINARY masktest [BINARY::masktest] diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c new file mode 100644 index 0000000000..629c04d073 --- /dev/null +++ b/source4/torture/gentest_smb2.c @@ -0,0 +1,1966 @@ +/* + Unix SMB/CIFS implementation. + + generic testing tool - version with SMB2 support + + Copyright (C) Andrew Tridgell 2003-2008 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . +*/ + +#include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "lib/events/events.h" +#include "system/time.h" +#include "system/filesys.h" +#include "libcli/raw/request.h" +#include "libcli/libcli.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "librpc/gen_ndr/security.h" +#include "auth/credentials/credentials.h" +#include "libcli/resolve/resolve.h" +#include "auth/gensec/gensec.h" +#include "param/param.h" +#include "dynconfig.h" + +#define NSERVERS 2 +#define NINSTANCES 2 + +/* global options */ +static struct gentest_options { + bool showall; + bool analyze; + bool analyze_always; + bool analyze_continuous; + uint_t max_open_handles; + uint_t seed; + uint_t numops; + bool use_oplocks; + char **ignore_patterns; + const char *seeds_file; + bool use_preset_seeds; + bool fast_reconnect; +} options; + +/* mapping between open handles on the server and local handles */ +static struct { + bool active; + uint_t instance; + struct smb2_handle server_handle[NSERVERS]; + const char *name; +} *open_handles; +static uint_t num_open_handles; + +/* state information for the servers. We open NINSTANCES connections to + each server */ +static struct { + struct smb2_tree *tree[NINSTANCES]; + char *server_name; + char *share_name; + struct cli_credentials *credentials; +} servers[NSERVERS]; + +/* the seeds and flags for each operation */ +static struct { + uint_t seed; + bool disabled; +} *op_parms; + + +/* oplock break info */ +static struct { + bool got_break; + struct smb2_handle server_handle; + uint16_t handle; + uint8_t level; + bool do_close; +} oplocks[NSERVERS][NINSTANCES]; + +/* change notify reply info */ +static struct { + int notify_count; + NTSTATUS status; + union smb_notify notify; +} notifies[NSERVERS][NINSTANCES]; + +/* info relevant to the current operation */ +static struct { + const char *name; + uint_t seed; + NTSTATUS status; + uint_t opnum; + TALLOC_CTX *mem_ctx; +} current_op; + +static struct smb2_handle bad_smb2_handle; + + +#define BAD_HANDLE 0xFFFE + +static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private); +static void idle_func(struct smb2_transport *transport, void *private); + +/* + check if a string should be ignored. This is used as the basis + for all error ignore settings +*/ +static bool ignore_pattern(const char *str) +{ + int i; + if (!options.ignore_patterns) return false; + + for (i=0;options.ignore_patterns[i];i++) { + if (strcmp(options.ignore_patterns[i], str) == 0 || + gen_fnmatch(options.ignore_patterns[i], str) == 0) { + DEBUG(2,("Ignoring '%s'\n", str)); + return true; + } + } + return false; +} + +/***************************************************** +connect to the servers +*******************************************************/ +static bool connect_servers_fast(void) +{ + int h, i; + + /* close all open files */ + for (h=0;husername, j); + + cli_credentials_set_workstation(servers[i].credentials, + "gentest", CRED_SPECIFIED); + + status = smb2_connect(NULL, servers[i].server_name, + servers[i].share_name, + lp_resolve_context(lp_ctx), + servers[i].credentials, + &servers[i].tree[j], + ev); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to connect to \\\\%s\\%s - %s\n", + servers[i].server_name, servers[i].share_name, + nt_errstr(status)); + return false; + } + +// smb2_oplock_handler(servers[i].cli[j]->transport, oplock_handler, NULL); + smb2_transport_idle_handler(servers[i].tree[j]->session->transport, idle_func, 50000, NULL); + } + } + + return true; +} + +/* + work out the time skew between the servers - be conservative +*/ +static uint_t time_skew(void) +{ + uint_t ret; + ret = labs(servers[0].tree[0]->session->transport->negotiate.system_time - + servers[1].tree[0]->session->transport->negotiate.system_time); + return ret + 300; +} + + +static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2) +{ + return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0; +} + +/* + turn a server handle into a local handle +*/ +static uint_t fnum_to_handle(int server, int instance, struct smb2_handle server_handle) +{ + uint_t i; + for (i=0;i 0 && count++ < 10*options.max_open_handles) { + h = random() % options.max_open_handles; + if (open_handles[h].active && + open_handles[h].instance == instance) { + return h; + } + } + return BAD_HANDLE; +} + +/* + return a file handle, but skewed so we don't close the last + couple of handles too readily +*/ +static uint16_t gen_fnum_close(int instance) +{ + if (num_open_handles < 3) { + if (gen_chance(80)) return BAD_HANDLE; + } + + return gen_fnum(instance); +} + +/* + generate an integer in a specified range +*/ +static int gen_int_range(uint_t min, uint_t max) +{ + uint_t r = random(); + return min + (r % (1+max-min)); +} + +/* + return a fnum for use as a root fid + be careful to call GEN_SET_FNUM() when you use this! +*/ +static uint16_t gen_root_fid(int instance) +{ + if (gen_chance(5)) return gen_fnum(instance); + return 0; +} + +/* + generate a file offset +*/ +static int gen_offset(void) +{ + if (gen_chance(20)) return 0; + return gen_int_range(0, 1024*1024); +} + +/* + generate a io count +*/ +static int gen_io_count(void) +{ + if (gen_chance(20)) return 0; + return gen_int_range(0, 4096); +} + +/* + generate a filename +*/ +static const char *gen_fname(void) +{ + const char *names[] = {"gentest\\gentest.dat", + "gentest\\foo", + "gentest\\foo2.sym", + "gentest\\foo3.dll", + "gentest\\foo4", + "gentest\\foo4:teststream1", + "gentest\\foo4:teststream2", + "gentest\\foo5.exe", + "gentest\\foo5.exe:teststream3", + "gentest\\foo5.exe:teststream4", + "gentest\\foo6.com", + "gentest\\blah", + "gentest\\blah\\blergh.txt", + "gentest\\blah\\blergh2", + "gentest\\blah\\blergh3.txt", + "gentest\\blah\\blergh4", + "gentest\\blah\\blergh5.txt", + "gentest\\blah\\blergh5", + "gentest\\blah\\.", +#if 0 + /* this causes problem with w2k3 */ + "gentest\\blah\\..", +#endif + "gentest\\a_very_long_name.bin", + "gentest\\x.y", + "gentest\\blah"}; + int i; + + do { + i = gen_int_range(0, ARRAY_SIZE(names)-1); + } while (ignore_pattern(names[i])); + + return names[i]; +} + +/* + generate a filename with a higher chance of choosing an already + open file +*/ +static const char *gen_fname_open(int instance) +{ + uint16_t h; + h = gen_fnum(instance); + if (h == BAD_HANDLE) { + return gen_fname(); + } + return open_handles[h].name; +} + +/* + generate a wildcard pattern +*/ +static const char *gen_pattern(void) +{ + int i; + const char *names[] = {"gentest\\*.dat", + "gentest\\*", + "gentest\\*.*", + "gentest\\blah\\*.*", + "gentest\\blah\\*", + "gentest\\?"}; + + if (gen_chance(50)) return gen_fname(); + + do { + i = gen_int_range(0, ARRAY_SIZE(names)-1); + } while (ignore_pattern(names[i])); + + return names[i]; +} + +static uint32_t gen_bits_levels(int nlevels, ...) +{ + va_list ap; + uint32_t pct; + uint32_t mask; + int i; + va_start(ap, nlevels); + for (i=0;isession->transport) { + // smb2_transport_process(servers[i].tree[j]->session->transport); + } + } + } + +} + + +/* + compare NTSTATUS, using checking ignored patterns +*/ +static bool compare_status(NTSTATUS status1, NTSTATUS status2) +{ + if (NT_STATUS_EQUAL(status1, status2)) return true; + + /* one code being an error and the other OK is always an error */ + if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) return false; + + /* if we are ignoring one of the status codes then consider this a match */ + if (ignore_pattern(nt_errstr(status1)) || + ignore_pattern(nt_errstr(status2))) { + return true; + } + return false; +} + + +/* + check for pending packets on all connections +*/ +static void check_pending(void) +{ + int i, j; + + msleep(20); + + for (j=0;jsession->transport); + } + } +} + +/* + check that the same oplock breaks have been received by all instances +*/ +static bool check_oplocks(const char *call) +{ +#if 0 + int i, j; + int tries = 0; + +again: + check_pending(); + + for (j=0;j time_skew() && \ + !ignore_pattern(#field)) { \ + printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ + (int)parm[0].field, (int)parm[1].field); \ + return false; \ + } \ +} while(0) + +#define CHECK_NTTIMES_EQUAL(field) do { \ + if (labs(nt_time_to_unix(parm[0].field) - \ + nt_time_to_unix(parm[1].field)) > time_skew() && \ + !ignore_pattern(#field)) { \ + printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ + (int)nt_time_to_unix(parm[0].field), \ + (int)nt_time_to_unix(parm[1].field)); \ + return false; \ + } \ +} while(0) + +/* + generate ntcreatex operations +*/ +static bool handler_ntcreatex(int instance) +{ + struct smb2_create parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + ZERO_STRUCT(parm[0]); + parm[0].in.security_flags = gen_bits_levels(3, 70, 0x0, 70, 0x3, 100, 0xFF); + parm[0].in.oplock_level = gen_bits_levels(3, 70, 0x0, 70, 0x9, 100, 0xFF); + parm[0].in.impersonation_level = gen_bits_levels(3, 70, 0x0, 70, 0x3, 100, 0xFFFFFFFF); + parm[0].in.create_flags = gen_bits_levels(2, 80, 0x0, 100, 0xFFFFFFFF); + if (gen_chance(2)) { + parm[0].in.create_flags |= gen_bits_mask(0xFFFFFFFF); + } + parm[0].in.reserved = gen_bits_levels(2, 80, 0x0, 100, 0xFFFFFFFF); + if (gen_chance(2)) { + parm[0].in.reserved |= gen_bits_mask(0xFFFFFFFF); + } + parm[0].in.desired_access = gen_access_mask(); + parm[0].in.file_attributes = gen_attrib(); + parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF); + parm[0].in.create_disposition = gen_open_disp(); + parm[0].in.create_options = gen_create_options(); + parm[0].in.fname = gen_fname_open(instance); + + if (!options.use_oplocks) { + /* mask out oplocks */ + parm[0].in.oplock_level = 0; + } + + GEN_COPY_PARM; + GEN_CALL(smb2_create(tree, current_op.mem_ctx, &parm[i])); + + CHECK_EQUAL(out.oplock_level); + CHECK_EQUAL(out.reserved); + CHECK_EQUAL(out.create_action); + CHECK_NTTIMES_EQUAL(out.create_time); + CHECK_NTTIMES_EQUAL(out.access_time); + CHECK_NTTIMES_EQUAL(out.write_time); + CHECK_NTTIMES_EQUAL(out.change_time); + CHECK_EQUAL(out.alloc_size); + CHECK_EQUAL(out.size); + CHECK_EQUAL(out.file_attr); + CHECK_EQUAL(out.reserved2); + + /* ntcreatex creates a new file handle */ + ADD_HANDLE(parm[0].in.fname, out.file.handle); + + return true; +} + +/* + generate close operations +*/ +static bool handler_close(int instance) +{ + struct smb2_close parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + ZERO_STRUCT(parm[0]); + parm[0].in.file.handle.data[0] = gen_fnum_close(instance); + parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF); + + GEN_COPY_PARM; + GEN_SET_FNUM(in.file.handle); + GEN_CALL(smb2_close(tree, &parm[i])); + + CHECK_EQUAL(out.flags); + CHECK_EQUAL(out._pad); + CHECK_NTTIMES_EQUAL(out.create_time); + CHECK_NTTIMES_EQUAL(out.access_time); + CHECK_NTTIMES_EQUAL(out.write_time); + CHECK_NTTIMES_EQUAL(out.change_time); + CHECK_EQUAL(out.alloc_size); + CHECK_EQUAL(out.size); + CHECK_EQUAL(out.file_attr); + + REMOVE_HANDLE(in.file.handle); + + return true; +} + +#if 0 +/* + generate read operations +*/ +static bool handler_read(int instance) +{ + union smb_read parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].readx.level = RAW_READ_READX; + parm[0].readx.in.file.fnum = gen_fnum(instance); + parm[0].readx.in.offset = gen_offset(); + parm[0].readx.in.mincnt = gen_io_count(); + parm[0].readx.in.maxcnt = gen_io_count(); + parm[0].readx.in.remaining = gen_io_count(); + parm[0].readx.in.read_for_execute = gen_bool(); + parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t, + MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt)); + + GEN_COPY_PARM; + GEN_SET_FNUM(readx.in.file.fnum); + GEN_CALL(smb_raw_read(tree, &parm[i])); + + CHECK_EQUAL(readx.out.remaining); + CHECK_EQUAL(readx.out.compaction_mode); + CHECK_EQUAL(readx.out.nread); + + return true; +} + +/* + generate write operations +*/ +static bool handler_write(int instance) +{ + union smb_write parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].writex.level = RAW_WRITE_WRITEX; + parm[0].writex.in.file.fnum = gen_fnum(instance); + parm[0].writex.in.offset = gen_offset(); + parm[0].writex.in.wmode = gen_bits_mask(0xFFFF); + parm[0].writex.in.remaining = gen_io_count(); + parm[0].writex.in.count = gen_io_count(); + parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count); + + GEN_COPY_PARM; + GEN_SET_FNUM(writex.in.file.fnum); + GEN_CALL(smb_raw_write(tree, &parm[i])); + + CHECK_EQUAL(writex.out.nwritten); + CHECK_EQUAL(writex.out.remaining); + + return true; +} + +/* + generate lockingx operations +*/ +static bool handler_lock(int instance) +{ + union smb_lock parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + int n, nlocks; + + parm[0].lockx.level = RAW_LOCK_LOCKX; + parm[0].lockx.in.file.fnum = gen_fnum(instance); + parm[0].lockx.in.mode = gen_lock_mode(); + parm[0].lockx.in.timeout = gen_timeout(); + do { + /* make sure we don't accidentially generate an oplock + break ack - otherwise the server can just block forever */ + parm[0].lockx.in.ulock_cnt = gen_lock_count(); + parm[0].lockx.in.lock_cnt = gen_lock_count(); + nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt; + } while (nlocks == 0); + + if (nlocks > 0) { + parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx, + struct smb_lock_entry, + nlocks); + for (n=0;ngeneric.level = levels[i].level; +} + +/* + compare returned fileinfo structures +*/ +static bool cmp_fileinfo(int instance, + union smb_fileinfo parm[NSERVERS], + NTSTATUS status[NSERVERS]) +{ + int i; + + switch (parm[0].generic.level) { + case RAW_FILEINFO_GENERIC: + return false; + + case RAW_FILEINFO_GETATTR: + CHECK_EQUAL(getattr.out.attrib); + CHECK_EQUAL(getattr.out.size); + CHECK_TIMES_EQUAL(getattr.out.write_time); + break; + + case RAW_FILEINFO_GETATTRE: + CHECK_TIMES_EQUAL(getattre.out.create_time); + CHECK_TIMES_EQUAL(getattre.out.access_time); + CHECK_TIMES_EQUAL(getattre.out.write_time); + CHECK_EQUAL(getattre.out.size); + CHECK_EQUAL(getattre.out.alloc_size); + CHECK_EQUAL(getattre.out.attrib); + break; + + case RAW_FILEINFO_STANDARD: + CHECK_TIMES_EQUAL(standard.out.create_time); + CHECK_TIMES_EQUAL(standard.out.access_time); + CHECK_TIMES_EQUAL(standard.out.write_time); + CHECK_EQUAL(standard.out.size); + CHECK_EQUAL(standard.out.alloc_size); + CHECK_EQUAL(standard.out.attrib); + break; + + case RAW_FILEINFO_EA_SIZE: + CHECK_TIMES_EQUAL(ea_size.out.create_time); + CHECK_TIMES_EQUAL(ea_size.out.access_time); + CHECK_TIMES_EQUAL(ea_size.out.write_time); + CHECK_EQUAL(ea_size.out.size); + CHECK_EQUAL(ea_size.out.alloc_size); + CHECK_EQUAL(ea_size.out.attrib); + CHECK_EQUAL(ea_size.out.ea_size); + break; + + case RAW_FILEINFO_ALL_EAS: + CHECK_EQUAL(all_eas.out.num_eas); + for (i=0;igeneric.level = levels[i].level; + + switch (info->generic.level) { + case RAW_SFILEINFO_SETATTR: + info->setattr.in.attrib = gen_attrib(); + info->setattr.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_SETATTRE: + info->setattre.in.create_time = gen_timet(); + info->setattre.in.access_time = gen_timet(); + info->setattre.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_STANDARD: + info->standard.in.create_time = gen_timet(); + info->standard.in.access_time = gen_timet(); + info->standard.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_EA_SET: { + static struct ea_struct ea; + info->ea_set.in.num_eas = 1; + info->ea_set.in.eas = &ea; + info->ea_set.in.eas[0] = gen_ea_struct(); + } + break; + case RAW_SFILEINFO_BASIC_INFO: + case RAW_SFILEINFO_BASIC_INFORMATION: + info->basic_info.in.create_time = gen_nttime(); + info->basic_info.in.access_time = gen_nttime(); + info->basic_info.in.write_time = gen_nttime(); + info->basic_info.in.change_time = gen_nttime(); + info->basic_info.in.attrib = gen_attrib(); + break; + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + info->disposition_info.in.delete_on_close = gen_bool(); + break; + case RAW_SFILEINFO_ALLOCATION_INFO: + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + info->allocation_info.in.alloc_size = gen_alloc_size(); + break; + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + info->end_of_file_info.in.size = gen_offset(); + break; + case RAW_SFILEINFO_RENAME_INFORMATION: + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + info->rename_information.in.overwrite = gen_bool(); + info->rename_information.in.root_fid = gen_root_fid(instance); + info->rename_information.in.new_name = gen_fname_open(instance); + break; + case RAW_SFILEINFO_POSITION_INFORMATION: + info->position_information.in.position = gen_offset(); + break; + case RAW_SFILEINFO_MODE_INFORMATION: + info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); + break; + case RAW_SFILEINFO_GENERIC: + case RAW_SFILEINFO_SEC_DESC: + case RAW_SFILEINFO_UNIX_BASIC: + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: + case RAW_SFILEINFO_1023: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1039: + case RAW_SFILEINFO_1040: + case RAW_SFILEINFO_UNIX_INFO2: + /* Untested */ + break; + } +} + +/* + generate setfileinfo operations +*/ +static bool handler_sfileinfo(int instance) +{ + union smb_setfileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.fnum = gen_fnum(instance); + + gen_setfileinfo(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_SET_FNUM(generic.in.file.fnum); + GEN_CALL(smb_raw_setfileinfo(tree, &parm[i])); + + return true; +} + +#endif + + +/* + wipe any relevant files +*/ +static void wipe_files(void) +{ + int i; + NTSTATUS status; + + for (i=0;i 0) { + printf("Deleted %d files on server %d\n", n, i); + } + } +} + +/* + dump the current seeds - useful for continuing a backtrack +*/ +static void dump_seeds(void) +{ + int i; + FILE *f; + + if (!options.seeds_file) { + return; + } + f = fopen("seeds.tmp", "w"); + if (!f) return; + + for (i=0;i 0 && base+chunk < options.numops && options.numops > 1; ) { + int i, max; + + chunk = MIN(chunk, options.numops / 2); + + /* mark this range as disabled */ + max = MIN(options.numops, base+chunk); + for (i=base;i 0); + + printf("Reduced to %d ops\n", options.numops); + ret = run_test(ev, lp_ctx); + if (ret != options.numops - 1) { + printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops); + } +} + +/* + start the main gentest process +*/ +static bool start_gentest(struct event_context *ev, + struct loadparm_context *lp_ctx) +{ + int op; + int ret; + + /* allocate the open_handles array */ + open_handles = calloc(options.max_open_handles, sizeof(open_handles[0])); + + srandom(options.seed); + op_parms = calloc(options.numops, sizeof(op_parms[0])); + + /* generate the seeds - after this everything is deterministic */ + if (options.use_preset_seeds) { + int numops; + char **preset = file_lines_load(options.seeds_file, &numops, NULL); + if (!preset) { + printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno)); + exit(1); + } + if (numops < options.numops) { + options.numops = numops; + } + for (op=0;op "); + + lp_ctx = cmdline_lp_ctx; + servers[0].credentials = cli_credentials_init(talloc_autofree_context()); + servers[1].credentials = cli_credentials_init(talloc_autofree_context()); + cli_credentials_guess(servers[0].credentials, lp_ctx); + cli_credentials_guess(servers[1].credentials, lp_ctx); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_UNCLIST: + lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc)); + break; + case 'U': + if (username_count == 2) { + usage(pc); + exit(1); + } + cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED); + username_count++; + break; + } + } + + if (ignore_file) { + options.ignore_patterns = file_lines_load(ignore_file, NULL, NULL); + } + + argv_new = discard_const_p(char *, poptGetArgs(pc)); + argc_new = argc; + for (i=0; i= 3)) { + usage(pc); + exit(1); + } + + setlinebuf(stdout); + + setup_logging("gentest", DEBUG_STDOUT); + + if (argc < 3 || argv[1][0] == '-') { + usage(pc); + exit(1); + } + + setup_logging(argv[0], DEBUG_STDOUT); + + for (i=0;i Date: Tue, 20 May 2008 13:37:27 +1000 Subject: added SMB2 setpathinfo composite wrapper (This used to be commit e90c7587385598a1dd976c2420798f9bd682b43d) --- source4/libcli/smb_composite/smb2.c | 105 ++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/source4/libcli/smb_composite/smb2.c b/source4/libcli/smb_composite/smb2.c index 84b4f66b61..6e005e03c0 100644 --- a/source4/libcli/smb_composite/smb2.c +++ b/source4/libcli/smb_composite/smb2.c @@ -264,3 +264,108 @@ NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io) struct composite_context *c = smb2_composite_rmdir_send(tree, io); return composite_wait_free(c); } + + +/* + continue after the setfileinfo in a composite setpathinfo + */ +static void continue_setpathinfo_close(struct smb2_request *req) +{ + struct composite_context *ctx = talloc_get_type(req->async.private_data, + struct composite_context); + struct smb2_tree *tree = req->tree; + struct smb2_close close_parm; + NTSTATUS status; + union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, + union smb_setfileinfo); + + status = smb2_setinfo_recv(req); + if (!NT_STATUS_IS_OK(status)) { + composite_error(ctx, status); + return; + } + + ZERO_STRUCT(close_parm); + close_parm.in.file.handle = io2->generic.in.file.handle; + + req = smb2_close_send(tree, &close_parm); + composite_continue_smb2(ctx, req, continue_close, ctx); +} + + +/* + continue after the create in a composite setpathinfo + */ +static void continue_setpathinfo(struct smb2_request *req) +{ + struct composite_context *ctx = talloc_get_type(req->async.private_data, + struct composite_context); + struct smb2_tree *tree = req->tree; + struct smb2_create create_parm; + NTSTATUS status; + union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, + union smb_setfileinfo); + + status = smb2_create_recv(req, ctx, &create_parm); + if (!NT_STATUS_IS_OK(status)) { + composite_error(ctx, status); + return; + } + + io2->generic.in.file.handle = create_parm.out.file.handle; + + req = smb2_setinfo_file_send(tree, io2); + composite_continue_smb2(ctx, req, continue_setpathinfo_close, ctx); +} + + +/* + composite SMB2 setpathinfo call +*/ +struct composite_context *smb2_composite_setpathinfo_send(struct smb2_tree *tree, + union smb_setfileinfo *io) +{ + struct composite_context *ctx; + struct smb2_create create_parm; + struct smb2_request *req; + union smb_setfileinfo *io2; + + ctx = composite_create(tree, tree->session->transport->socket->event.ctx); + if (ctx == NULL) return NULL; + + ZERO_STRUCT(create_parm); + create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; + create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; + create_parm.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create_parm.in.create_options = 0; + create_parm.in.fname = io->generic.in.file.path; + if (create_parm.in.fname[0] == '\\') { + create_parm.in.fname++; + } + + req = smb2_create_send(tree, &create_parm); + + io2 = talloc(ctx, union smb_setfileinfo); + if (composite_nomem(io2, ctx)) { + return ctx; + } + *io2 = *io; + + ctx->private_data = io2; + + composite_continue_smb2(ctx, req, continue_setpathinfo, ctx); + return ctx; +} + + +/* + composite setpathinfo call + */ +NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io) +{ + struct composite_context *c = smb2_composite_setpathinfo_send(tree, io); + return composite_wait_free(c); +} -- cgit From 430f4ef66635acbf7b2b8f6a90aed597d03f3aca Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 13:37:40 +1000 Subject: specify which server failed to deltree (This used to be commit aa9108374f0dda8510245a6e69a53189f55a81e3) --- source4/torture/gentest_smb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index 629c04d073..4b763fc011 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -1555,7 +1555,7 @@ static void wipe_files(void) } status = smb2_util_mkdir(servers[i].tree[0], "gentest"); if (NT_STATUS_IS_ERR(status)) { - printf("Failed to create gentest - %s\n", nt_errstr(status)); + printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status)); exit(1); } if (n > 0) { -- cgit From 2214e6d9bfdc52db0558e831691b4500405ab9ae Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 13:37:51 +1000 Subject: added smb2_util_setatr (This used to be commit d4f41db964ce82c8889017d0f932d60100b3cd32) --- source4/libcli/smb2/util.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source4/libcli/smb2/util.c b/source4/libcli/smb2/util.c index 0fc03b48c5..9eb344e83f 100644 --- a/source4/libcli/smb2/util.c +++ b/source4/libcli/smb2/util.c @@ -82,6 +82,22 @@ NTSTATUS smb2_util_mkdir(struct smb2_tree *tree, const char *dname) } +/* + set file attribute with SMB2 +*/ +NTSTATUS smb2_util_setatr(struct smb2_tree *tree, const char *name, uint32_t attrib) +{ + union smb_setfileinfo io; + + ZERO_STRUCT(io); + io.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; + io.basic_info.in.file.path = name; + io.basic_info.in.attrib = attrib; + + return smb2_composite_setpathinfo(tree, &io); +} + + /* @@ -151,6 +167,12 @@ int smb2_deltree(struct smb2_tree *tree, const char *dname) } name = talloc_asprintf(tmp_ctx, "%s\\%s", dname, list[i].name_info.name.s); status = smb2_util_unlink(tree, name); + if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { + /* it could be read-only */ + status = smb2_util_setatr(tree, name, FILE_ATTRIBUTE_NORMAL); + status = smb2_util_unlink(tree, name); + } + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { int ret; ret = smb2_deltree(tree, name); -- cgit From 5ca6f42510cd746f62d3973a3c01085876c71b7b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 May 2008 15:16:53 +1000 Subject: added read and write handlers. Fixed --analyse (This used to be commit c05ed7bb9ae7211a7001fd0a3403744ba4f6dda0) --- source4/torture/gentest_smb2.c | 94 ++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index 4b763fc011..9c4be90b3c 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -41,18 +41,18 @@ /* global options */ static struct gentest_options { - bool showall; - bool analyze; - bool analyze_always; - bool analyze_continuous; + int showall; + int analyze; + int analyze_always; + int analyze_continuous; uint_t max_open_handles; uint_t seed; uint_t numops; - bool use_oplocks; + int use_oplocks; char **ignore_patterns; const char *seeds_file; - bool use_preset_seeds; - bool fast_reconnect; + int use_preset_seeds; + int fast_reconnect; } options; /* mapping between open handles on the server and local handles */ @@ -359,7 +359,7 @@ static uint16_t gen_fnum_close(int instance) /* generate an integer in a specified range */ -static int gen_int_range(uint_t min, uint_t max) +static int gen_int_range(uint64_t min, uint64_t max) { uint_t r = random(); return min + (r % (1+max-min)); @@ -381,6 +381,7 @@ static uint16_t gen_root_fid(int instance) static int gen_offset(void) { if (gen_chance(20)) return 0; +// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF); return gen_int_range(0, 1024*1024); } @@ -390,6 +391,7 @@ static int gen_offset(void) static int gen_io_count(void) { if (gen_chance(20)) return 0; +// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF); return gen_int_range(0, 4096); } @@ -1078,32 +1080,31 @@ static bool handler_close(int instance) return true; } -#if 0 /* generate read operations */ static bool handler_read(int instance) { - union smb_read parm[NSERVERS]; + struct smb2_read parm[NSERVERS]; NTSTATUS status[NSERVERS]; - parm[0].readx.level = RAW_READ_READX; - parm[0].readx.in.file.fnum = gen_fnum(instance); - parm[0].readx.in.offset = gen_offset(); - parm[0].readx.in.mincnt = gen_io_count(); - parm[0].readx.in.maxcnt = gen_io_count(); - parm[0].readx.in.remaining = gen_io_count(); - parm[0].readx.in.read_for_execute = gen_bool(); - parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t, - MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt)); + parm[0].in.file.handle.data[0] = gen_fnum(instance); + parm[0].in.reserved = gen_bits_mask2(0x0, 0xFF); + parm[0].in.length = gen_io_count(); + parm[0].in.offset = gen_offset(); + parm[0].in.min_count = gen_io_count(); + parm[0].in.channel = gen_bits_mask2(0x0, 0xFFFFFFFF); + parm[0].in.remaining = gen_bits_mask2(0x0, 0xFFFFFFFF); + parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF); + parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF); GEN_COPY_PARM; - GEN_SET_FNUM(readx.in.file.fnum); - GEN_CALL(smb_raw_read(tree, &parm[i])); + GEN_SET_FNUM(in.file.handle); + GEN_CALL(smb2_read(tree, current_op.mem_ctx, &parm[i])); - CHECK_EQUAL(readx.out.remaining); - CHECK_EQUAL(readx.out.compaction_mode); - CHECK_EQUAL(readx.out.nread); + CHECK_EQUAL(out.remaining); + CHECK_EQUAL(out.reserved); + CHECK_EQUAL(out.data.length); return true; } @@ -1113,27 +1114,28 @@ static bool handler_read(int instance) */ static bool handler_write(int instance) { - union smb_write parm[NSERVERS]; + struct smb2_write parm[NSERVERS]; NTSTATUS status[NSERVERS]; - parm[0].writex.level = RAW_WRITE_WRITEX; - parm[0].writex.in.file.fnum = gen_fnum(instance); - parm[0].writex.in.offset = gen_offset(); - parm[0].writex.in.wmode = gen_bits_mask(0xFFFF); - parm[0].writex.in.remaining = gen_io_count(); - parm[0].writex.in.count = gen_io_count(); - parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count); + parm[0].in.file.handle.data[0] = gen_fnum(instance); + parm[0].in.offset = gen_offset(); + parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF); + parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF); + parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL, + gen_io_count()); GEN_COPY_PARM; - GEN_SET_FNUM(writex.in.file.fnum); - GEN_CALL(smb_raw_write(tree, &parm[i])); + GEN_SET_FNUM(in.file.handle); + GEN_CALL(smb2_write(tree, &parm[i])); - CHECK_EQUAL(writex.out.nwritten); - CHECK_EQUAL(writex.out.remaining); + CHECK_EQUAL(out._pad); + CHECK_EQUAL(out.nwritten); + CHECK_EQUAL(out.unknown1); return true; } +#if 0 /* generate lockingx operations */ @@ -1379,24 +1381,6 @@ static bool cmp_fileinfo(int instance, return true; } -/* - generate qpathinfo operations -*/ -static bool handler_qpathinfo(int instance) -{ - union smb_fileinfo parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - parm[0].generic.in.file.path = gen_fname_open(instance); - - gen_fileinfo(instance, &parm[0]); - - GEN_COPY_PARM; - GEN_CALL(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i])); - - return cmp_fileinfo(instance, parm, status); -} - /* generate qfileinfo operations */ @@ -1597,6 +1581,8 @@ static struct { } gen_ops[] = { {"NTCREATEX", handler_ntcreatex}, {"CLOSE", handler_close}, + {"READ", handler_read}, + {"WRITE", handler_write}, }; -- cgit From 52f0af3990f79dfc6b2e784eed9e58a2a705d1ea Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 20 May 2008 15:28:26 +1000 Subject: Fix irpc GetDC requests. We would return NT_STATUS_NO_LOGON_SERVERS in all cases, which was less than helpful. Andrew Bartlett (This used to be commit 5dfa316b3636718ffc6fd26cf7a397a797bd2ac1) --- source4/nbt_server/irpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/nbt_server/irpc.c b/source4/nbt_server/irpc.c index b14610b2df..8f1f74afcf 100644 --- a/source4/nbt_server/irpc.c +++ b/source4/nbt_server/irpc.c @@ -84,8 +84,6 @@ static void getdc_recv_netlogon_reply(struct dgram_mailslot_handler *dgmslot, goto done; } - status = NT_STATUS_NO_LOGON_SERVERS; - p = netlogon.samlogon.nt4.server; DEBUG(10, ("NTLOGON_SAM_LOGON_REPLY: server: %s, user: %s, " @@ -102,6 +100,8 @@ static void getdc_recv_netlogon_reply(struct dgram_mailslot_handler *dgmslot, goto done; } + status = NT_STATUS_OK; + done: irpc_send_reply(s->msg, status); } -- cgit From 276fa76fa98355cc09dad4d069fd64d0be7f8655 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 20 May 2008 12:59:04 +0200 Subject: Change wks password in rpc-bench-schannel1 Prove that a workstation password change does not affect existing schannel connections (This used to be commit f72dc52ccc426c8057b91b4699dfeda7d9e9b864) --- source4/torture/rpc/schannel.c | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index f0279f0d04..a8f70b2ea9 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -738,6 +738,70 @@ bool torture_rpc_schannel_bench1(struct torture_context *torture) } torture_assert_ntstatus_ok(torture, s->error, "Failed establish a connect"); + /* + * Change the workstation password after establishing the netlogon + * schannel connections to prove that existing connections are not + * affected by a wks pwchange. + */ + + { + struct netr_ServerPasswordSet pwset; + char *password = generate_random_str(s->join_ctx1, 8); + struct creds_CredentialState *creds_state; + struct dcerpc_pipe *net_pipe; + + status = dcerpc_pipe_connect_b(s, &net_pipe, s->b, + &ndr_table_netlogon, + s->wks_creds1, + torture->ev, torture->lp_ctx); + + torture_assert_ntstatus_ok(torture, status, + "dcerpc_pipe_connect_b failed"); + + pwset.in.server_name = talloc_asprintf( + net_pipe, "\\\\%s", dcerpc_server_name(net_pipe)); + pwset.in.computer_name = + cli_credentials_get_workstation(s->wks_creds1); + pwset.in.account_name = talloc_asprintf( + net_pipe, "%s$", pwset.in.computer_name); + pwset.in.secure_channel_type = SEC_CHAN_WKSTA; + E_md4hash(password, pwset.in.new_password.hash); + + creds_state = cli_credentials_get_netlogon_creds( + s->wks_creds1); + creds_des_encrypt(creds_state, &pwset.in.new_password); + creds_client_authenticator(creds_state, &pwset.in.credential); + + status = dcerpc_netr_ServerPasswordSet(net_pipe, torture, &pwset); + torture_assert_ntstatus_ok(torture, status, + "ServerPasswordSet failed"); + + if (!creds_client_check(creds_state, + &pwset.out.return_authenticator.cred)) { + printf("Credential chaining failed\n"); + } + + cli_credentials_set_password(s->wks_creds1, password, + CRED_SPECIFIED); + + talloc_free(net_pipe); + + /* Just as a test, connect with the new creds */ + + talloc_free(s->wks_creds1->netlogon_creds); + s->wks_creds1->netlogon_creds = NULL; + + status = dcerpc_pipe_connect_b(s, &net_pipe, s->b, + &ndr_table_netlogon, + s->wks_creds1, + torture->ev, torture->lp_ctx); + + torture_assert_ntstatus_ok(torture, status, + "dcerpc_pipe_connect_b failed"); + + talloc_free(net_pipe); + } + torture_comment(torture, "Start looping LogonSamLogonEx on %d connections for %d secs\n", s->nprocs, s->timelimit); for (i=0; i < s->nprocs; i++) { -- cgit From 9a975a868e949e61cb011422363cd07b4ec0ce43 Mon Sep 17 00:00:00 2001 From: James Peach Date: Tue, 20 May 2008 10:54:45 -0700 Subject: smbtorture: Add RAW-BENCH-TCON benchmark. Add a simple test to benchmark the rate at which a server can accept new tree connections. You can tune the length of time to run the benchmark for and the number of parallel connections to make. (This used to be commit ea3f4b93057e85c4ea516cc77dd0f293016d520c) --- source4/lib/util/time.c | 2 +- source4/lib/util/time.h | 2 +- source4/torture/config.mk | 1 + source4/torture/raw/raw.c | 2 + source4/torture/raw/tconrate.c | 201 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 source4/torture/raw/tconrate.c diff --git a/source4/lib/util/time.c b/source4/lib/util/time.c index a181885806..978d73cc0a 100644 --- a/source4/lib/util/time.c +++ b/source4/lib/util/time.c @@ -376,7 +376,7 @@ _PUBLIC_ NTTIME pull_nttime(uint8_t *base, uint16_t offset) /** return (tv1 - tv2) in microseconds */ -_PUBLIC_ int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2) +_PUBLIC_ int64_t usec_time_diff(const struct timeval *tv1, const struct timeval *tv2) { int64_t sec_diff = tv1->tv_sec - tv2->tv_sec; return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec); diff --git a/source4/lib/util/time.h b/source4/lib/util/time.h index 1ab976ca78..e4008c5782 100644 --- a/source4/lib/util/time.h +++ b/source4/lib/util/time.h @@ -127,7 +127,7 @@ _PUBLIC_ NTTIME nttime_from_string(const char *s); /** return (tv1 - tv2) in microseconds */ -_PUBLIC_ int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2); +_PUBLIC_ int64_t usec_time_diff(const struct timeval *tv1, const struct timeval *tv2); /** return a zero timeval diff --git a/source4/torture/config.mk b/source4/torture/config.mk index e82cb4523d..2857b99582 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -70,6 +70,7 @@ TORTURE_RAW_OBJ_FILES = $(addprefix $(torturesrcdir)/raw/, \ pingpong.o \ lockbench.o \ lookuprate.o \ + tconrate.o \ openbench.o \ rename.o \ eas.o \ diff --git a/source4/torture/raw/raw.c b/source4/torture/raw/raw.c index c6133081b0..0a7fc3ebfd 100644 --- a/source4/torture/raw/raw.c +++ b/source4/torture/raw/raw.c @@ -35,6 +35,8 @@ NTSTATUS torture_raw_init(void) torture_suite_add_simple_test(suite, "BENCH-OPEN", torture_bench_open); torture_suite_add_simple_test(suite, "BENCH-LOOKUP", torture_bench_lookup); + torture_suite_add_simple_test(suite, "BENCH-TCON", + torture_bench_treeconnect); torture_suite_add_simple_test(suite, "OFFLINE", torture_test_offline); torture_suite_add_1smb_test(suite, "QFSINFO", torture_raw_qfsinfo); torture_suite_add_1smb_test(suite, "QFILEINFO", torture_raw_qfileinfo); diff --git a/source4/torture/raw/tconrate.c b/source4/torture/raw/tconrate.c new file mode 100644 index 0000000000..6f0ba0d617 --- /dev/null +++ b/source4/torture/raw/tconrate.c @@ -0,0 +1,201 @@ +/* + SMB tree connection rate test + + Copyright (C) 2006-2007 James Peach + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . +*/ + +#include "includes.h" +#include "libcli/libcli.h" +#include "libcli/resolve/resolve.h" +#include "torture/smbtorture.h" +#include "lib/cmdline/popt_common.h" +#include "param/param.h" + +#include "system/filesys.h" +#include "system/shmem.h" + +#define TIME_LIMIT_SECS 30 +#define usec_to_sec(s) ((s) / 1000000) +#define sec_to_usec(s) ((s) * 1000000) + +/* Map a shared memory buffer of at least nelem counters. */ +static void * map_count_buffer(unsigned nelem, size_t elemsz) +{ + void * buf; + size_t bufsz; + size_t pagesz = getpagesize(); + + bufsz = nelem * elemsz; + bufsz = (bufsz + pagesz) % pagesz; /* round up to pagesz */ + +#ifdef MAP_ANON + /* BSD */ + buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, + -1 /* fd */, 0 /* offset */); +#else + buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + open("/dev/zero", O_RDWR), 0 /* offset */); +#endif + + if (buf == MAP_FAILED) { + printf("failed to map count buffer: %s\n", + strerror(errno)); + return NULL; + } + + return buf; + +} + +static int fork_tcon_client(struct torture_context *tctx, + int *tcon_count, unsigned tcon_timelimit, + const char *host, const char *share) +{ + pid_t child; + struct smbcli_state *cli; + struct timeval end; + struct timeval now; + struct smbcli_options options; + + lp_smbcli_options(tctx->lp_ctx, &options); + + child = fork(); + if (child == -1) { + printf("failed to fork child: %s\n,", strerror(errno)); + return -1; + } else if (child != 0) { + /* Parent, just return. */ + return 0; + } + + /* Child. Just make as many connections as possible within the + * time limit. Don't bother synchronising the child start times + * because it's probably not work the effort, and a bit of startup + * jitter is probably a more realistic test. + */ + + + end = timeval_current(); + now = timeval_current(); + end.tv_sec += tcon_timelimit; + *tcon_count = 0; + + while (timeval_compare(&now, &end) == -1) { + NTSTATUS status; + + status = smbcli_full_connection(NULL, &cli, + host, lp_smb_ports(tctx->lp_ctx), share, + NULL, cmdline_credentials, + lp_resolve_context(tctx->lp_ctx), + tctx->ev, &options); + + if (!NT_STATUS_IS_OK(status)) { + printf("failed to connect to //%s/%s: %s\n", + host, share, nt_errstr(status)); + goto done; + } + + smbcli_tdis(cli); + + *tcon_count = *tcon_count + 1; + now = timeval_current(); + } + +done: + exit(0); +} + +static bool children_remain(void) +{ + /* Reap as many children as possible. */ + for (;;) { + pid_t ret = waitpid(-1, NULL, WNOHANG); + if (ret == 0) { + /* no children ready */ + return true; + } + if (ret == -1) { + /* no children left. maybe */ + return errno == ECHILD ? false : true; + } + } + + /* notreached */ + return false; +} + +static double rate_convert_secs(unsigned count, + const struct timeval *start, const struct timeval *end) +{ + return (double)count / + usec_to_sec((double)usec_time_diff(end, start)); +} + +/* Test the rate at which the server will accept connections. */ +bool torture_bench_treeconnect(struct torture_context *tctx) +{ + const char *host = torture_setting_string(tctx, "host", NULL); + const char *share = torture_setting_string(tctx, "share", NULL); + + int timelimit = torture_setting_int(tctx, "timelimit", + TIME_LIMIT_SECS); + int nprocs = torture_setting_int(tctx, "nprocs", 4); + + int *curr_counts = map_count_buffer(nprocs, sizeof(int)); + int *last_counts = talloc_array(NULL, int, nprocs); + + struct timeval now, last, start; + int i, delta; + + torture_assert(tctx, nprocs > 0, "bad proc count"); + torture_assert(tctx, timelimit > 0, "bad timelimit"); + torture_assert(tctx, curr_counts, "allocation failure"); + torture_assert(tctx, last_counts, "allocation failure"); + + start = last = timeval_current(); + for (i = 0; i < nprocs; ++i) { + fork_tcon_client(tctx, &curr_counts[i], timelimit, host, share); + } + + while (children_remain()) { + + sleep(1); + now = timeval_current(); + + for (i = 0, delta = 0; i < nprocs; ++i) { + delta += curr_counts[i] - last_counts[i]; + } + + printf("%u connections/sec\n", + (unsigned)rate_convert_secs(delta, &last, &now)); + + memcpy(last_counts, curr_counts, nprocs * sizeof(int)); + last = timeval_current(); + } + + now = timeval_current(); + + for (i = 0, delta = 0; i < nprocs; ++i) { + delta += curr_counts[i]; + } + + printf("TOTAL: %u connections/sec over %u secs\n", + (unsigned)rate_convert_secs(delta, &start, &now), + timelimit); + return true; +} + +/* vim: set sts=8 sw=8 : */ -- cgit From aa7e4b8e9cafaa5139b5111aa8ca042e6b6f65f4 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 20 May 2008 21:54:36 +0200 Subject: Fix nesting tdb_traverse in a transaction Calling tdb_traverse inside a transaction led to the transaction lock being held indefinitely. This was caused by the tdb_transaction_lock/unlock inside tdb_traverse: The transaction code holds the global lock at offset TRANSACTION_LOCK. The call to tdb_transaction_lock does nothing because the transaction_lock is already being held. tdb_transaction_unlock inside tdb_wrap resets tdb->have_transaction_lock but does not release the kernel-level fcntl lock. transaction_commit later on does not release that fcntl lock either, because tdb->have_transaction_lock was already reset by tdb_transaction(). This patch does fix that problem for me. An alternative would be to make tdb->have_transaction_lock a counter that can cope with proper nesting, maybe in other places as well. Volker (This used to be commit 89543005fe2e4934b3c560c937d49304a32a7fc2) --- source4/lib/tdb/common/traverse.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source4/lib/tdb/common/traverse.c b/source4/lib/tdb/common/traverse.c index 07b0c23858..5a31742e7b 100644 --- a/source4/lib/tdb/common/traverse.c +++ b/source4/lib/tdb/common/traverse.c @@ -232,20 +232,25 @@ int tdb_traverse(struct tdb_context *tdb, { struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; int ret; + int in_transaction = (tdb->transaction != NULL); if (tdb->read_only || tdb->traverse_read) { return tdb_traverse_read(tdb, fn, private_data); } - if (tdb_transaction_lock(tdb, F_WRLCK)) { - return -1; + if (!in_transaction) { + if (tdb_transaction_lock(tdb, F_WRLCK)) { + return -1; + } } tdb->traverse_write++; ret = tdb_traverse_internal(tdb, fn, private_data, &tl); tdb->traverse_write--; - tdb_transaction_unlock(tdb); + if (!in_transaction) { + tdb_transaction_unlock(tdb); + } return ret; } -- cgit From 6d4424cd45333c3029b0272528485dd2b3f8e620 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 20 May 2008 14:18:58 -0700 Subject: Convert in_transaction to a bool. Add the same fix Volker used for tdb_traverse() to tdb_traverse_read(). Jeremy. (This used to be commit e05ec3047c4fe0cc2e09a812830fc835dc35abea) --- source4/lib/tdb/common/traverse.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source4/lib/tdb/common/traverse.c b/source4/lib/tdb/common/traverse.c index 5a31742e7b..69c81e6e98 100644 --- a/source4/lib/tdb/common/traverse.c +++ b/source4/lib/tdb/common/traverse.c @@ -204,18 +204,23 @@ int tdb_traverse_read(struct tdb_context *tdb, { struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK }; int ret; + bool in_transaction = (tdb->transaction != NULL); /* we need to get a read lock on the transaction lock here to cope with the lock ordering semantics of solaris10 */ - if (tdb_transaction_lock(tdb, F_RDLCK)) { - return -1; + if (!in_transaction) { + if (tdb_transaction_lock(tdb, F_RDLCK)) { + return -1; + } } tdb->traverse_read++; ret = tdb_traverse_internal(tdb, fn, private_data, &tl); tdb->traverse_read--; - tdb_transaction_unlock(tdb); + if (!in_transaction) { + tdb_transaction_unlock(tdb); + } return ret; } @@ -232,7 +237,7 @@ int tdb_traverse(struct tdb_context *tdb, { struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; int ret; - int in_transaction = (tdb->transaction != NULL); + bool in_transaction = (tdb->transaction != NULL); if (tdb->read_only || tdb->traverse_read) { return tdb_traverse_read(tdb, fn, private_data); -- cgit