#include "smbprofile.h"
#include "../lib/tsocket/tsocket.h"
#include "lib/tevent_wait.h"
+#include "lib/util/tevent_ntstatus.h"
#include "libcli/smb/smb_signing.h"
#include "lib/util/sys_rw_data.h"
+#include "librpc/gen_ndr/open_files.h"
+#include "smb1_utils.h"
+#include "libcli/smb/smb2_posix.h"
/****************************************************************************
Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
}
/****************************************************************************
- Pull a string and check the path allowing a wilcard - provide for error return.
+ Pull a string and check the path allowing a wildcard - provide for error return.
Passes in posix flag.
****************************************************************************/
}
/****************************************************************************
- Pull a string and check the path allowing a wilcard - provide for error return.
+ Pull a string and check the path allowing a wildcard - provide for error return.
****************************************************************************/
size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
}
/****************************************************************************
- Pull a string and check the path allowing a wilcard - provide for error return.
+ Pull a string and check the path allowing a wildcard - provide for error return.
posix_pathnames version.
****************************************************************************/
void reply_tcon_and_X(struct smb_request *req)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
connection_struct *conn = req->conn;
const char *service = NULL;
TALLOC_CTX *ctx = talloc_tos();
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("smb_key_derivation failed: %s\n",
nt_errstr(status));
+ END_PROFILE(SMBtconX);
return;
}
optional_support |= SMB_EXTENDED_SIGNATURES;
if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
DEBUG(2,("Serving %s as a Dfs root\n",
- lp_servicename(ctx, SNUM(conn)) ));
+ lp_servicename(ctx, lp_sub, SNUM(conn)) ));
optional_support |= SMB_SHARE_IN_DFS;
}
void reply_ioctl(struct smb_request *req)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
connection_struct *conn = req->conn;
uint16_t device;
uint16_t function;
status = srvstr_push((char *)req->outbuf, req->flags2,
p+18,
lp_servicename(talloc_tos(),
+ lp_sub,
SNUM(conn)),
13, STR_TERMINATE|STR_ASCII, &len);
if (!NT_STATUS_IS_OK(status)) {
const char *p;
NTSTATUS status;
TALLOC_CTX *ctx = talloc_tos();
- bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
+ bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
START_PROFILE(SMBgetatr);
ZERO_STRUCT(write_time_ts);
fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
get_file_infos(fileid, 0, NULL, &write_time_ts);
- if (!null_timespec(write_time_ts)) {
+ if (!is_omit_timespec(&write_time_ts)) {
update_stat_ex_mtime(&smb_fname->st, write_time_ts);
}
}
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBsetatr);
+ init_smb_file_time(&ft);
if (req->wct < 2) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
}
}
- ft = (struct smb_file_time) {
- .mtime = convert_time_t_to_timespec(mtime)
- };
+ ft.mtime = time_t_to_full_timespec(mtime);
status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
bool mask_contains_wcard = False;
bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
TALLOC_CTX *ctx = talloc_tos();
- bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
- struct dptr_struct *dirptr = NULL;
+ bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
struct smbXsrv_connection *xconn = req->xconn;
struct smbd_server_connection *sconn = req->sconn;
+ files_struct *fsp = NULL;
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
START_PROFILE(SMBsearch);
goto out;
}
+ if (smbreq_bufrem(req, p) < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto out;
+ }
+
p++;
status_len = SVAL(p, 0);
p += 2;
/* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
if (status_len == 0) {
+ int ret;
struct smb_filename *smb_dname = NULL;
uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
ucf_flags_from_smb_request(req);
goto out;
}
+ /*
+ * As we've cut off the last component from
+ * smb_fname we need to re-stat smb_dname
+ * so FILE_OPEN disposition knows the directory
+ * exists.
+ */
+ if (req->posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn, smb_dname);
+ } else {
+ ret = SMB_VFS_STAT(conn, smb_dname);
+ }
+ if (ret == -1) {
+ nt_status = map_nt_error_from_unix(errno);
+ reply_nterror(req, nt_status);
+ goto out;
+ }
+
+ /*
+ * Open an fsp on this directory for the dptr.
+ */
+ nt_status = SMB_VFS_CREATE_FILE(
+ conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ smb_dname, /* dname */
+ FILE_LIST_DIRECTORY, /* access_mask */
+ FILE_SHARE_READ|
+ FILE_SHARE_WRITE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ FILE_DIRECTORY_FILE, /* create_options */
+ FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
+ NO_OPLOCK, /* oplock_request */
+ NULL, /* lease */
+ 0, /* allocation_size */
+ 0, /* private_flags */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ NULL, /* in_context */
+ NULL);/* out_context */
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DBG_ERR("failed to open directory %s\n",
+ smb_fname_str_dbg(smb_dname));
+ reply_nterror(req, nt_status);
+ goto out;
+ }
+
nt_status = dptr_create(conn,
NULL, /* req */
- NULL, /* fsp */
- smb_dname,
+ fsp, /* fsp */
True,
expect_close,
req->smbpid,
mask,
mask_contains_wcard,
dirtype,
- &dirptr);
+ &fsp->dptr);
TALLOC_FREE(smb_dname);
if (!NT_STATUS_IS_OK(nt_status)) {
+ /*
+ * Use NULL here for the first parameter (req)
+ * as this is not a client visible handle so
+ * can'tbe part of an SMB1 chain.
+ */
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
reply_nterror(req, nt_status);
goto out;
}
- dptr_num = dptr_dnum(dirptr);
+
+ dptr_num = dptr_dnum(fsp->dptr);
+
} else {
int status_dirtype;
const char *dirpath;
+ if (smbreq_bufrem(req, p) < 21) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto out;
+ }
+
memcpy(status,p,21);
status_dirtype = CVAL(status,0) & 0x1F;
if (status_dirtype != (dirtype & 0x1F)) {
dirtype = status_dirtype;
}
- dirptr = dptr_fetch(sconn, status+12,&dptr_num);
- if (!dirptr) {
+ fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
+ if (fsp == NULL) {
goto SearchEmpty;
}
dirpath = dptr_path(sconn, dptr_num);
maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- directory,lp_dont_descend(ctx, SNUM(conn))));
- if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
+ directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
+ if (in_list(directory, lp_dont_descend(ctx, lp_sub, SNUM(conn)),True)) {
check_descend = True;
}
for (i=numentries;(i<maxentries) && !finished;i++) {
finished = !get_dir_entry(ctx,
- dirptr,
+ fsp->dptr,
mask,
dirtype,
&fname,
SearchEmpty:
/* If we were called as SMBffirst with smb_search_id == NULL
- and no entries were found then return error and close dirptr
+ and no entries were found then return error and close fsp->dptr
(X/Open spec) */
if (numentries == 0) {
- dptr_close(sconn, &dptr_num);
+ dptr_num = -1;
+ if (fsp != NULL) {
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
} else if(expect_close && status_len == 0) {
/* Close the dptr - we know it's gone */
- dptr_close(sconn, &dptr_num);
+ dptr_num = -1;
+ if (fsp != NULL) {
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
}
- /* If we were called as SMBfunique, then we can close the dirptr now ! */
+ /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
if(dptr_num >= 0 && req->cmd == SMBfunique) {
- dptr_close(sconn, &dptr_num);
+ dptr_num = -1;
+ /* fsp may have been closed above. */
+ if (fsp != NULL) {
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
}
if ((numentries == 0) && !mask_contains_wcard) {
bool path_contains_wcard = False;
TALLOC_CTX *ctx = talloc_tos();
struct smbd_server_connection *sconn = req->sconn;
+ files_struct *fsp = NULL;
START_PROFILE(SMBfclose);
END_PROFILE(SMBfclose);
return;
}
+
+ if (smbreq_bufrem(req, p) < 3) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBfclose);
+ return;
+ }
+
p++;
status_len = SVAL(p,0);
p += 2;
return;
}
+ if (smbreq_bufrem(req, p) < 21) {
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBfclose);
+ return;
+ }
+
memcpy(status,p,21);
- if(dptr_fetch(sconn, status+12,&dptr_num)) {
- /* Close the dptr - we know it's gone */
- dptr_close(sconn, &dptr_num);
+ fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
+ if(fsp != NULL) {
+ /* Close the file - we know it's gone */
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ dptr_num = -1;
}
reply_outbuf(req, 1, 0);
/* We have re-scheduled this call. */
goto out;
}
- reply_openerror(req, status);
- goto out;
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ reply_openerror(req, status);
+ goto out;
+ }
+
+ fsp = fcb_or_dos_open(
+ req,
+ smb_fname,
+ access_mask,
+ create_options,
+ private_flags);
+ if (fsp == NULL) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ reply_openerror(req, status);
+ goto out;
+ }
}
/* Ensure we're pointing at the correct stat struct. */
/* We have re-scheduled this call. */
goto out;
}
- reply_openerror(req, status);
- goto out;
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ reply_openerror(req, status);
+ goto out;
+ }
+
+ fsp = fcb_or_dos_open(
+ req,
+ smb_fname,
+ access_mask,
+ create_options,
+ private_flags);
+ if (fsp == NULL) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ reply_openerror(req, status);
+ goto out;
+ }
+
+
+ smb_action = FILE_WAS_OPENED;
}
/* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
}
fattr = dos_mode(conn, fsp->fsp_name);
- mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
close_file(req, fsp, ERROR_CLOSE);
reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
+ mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
/* If the caller set the extended oplock request bit
and we granted one (by whatever means) - set the
Reply to a SMBulogoffX.
****************************************************************************/
-void reply_ulogoffX(struct smb_request *req)
+static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
+ struct smbXsrv_session *session);
+static void reply_ulogoffX_done(struct tevent_req *req);
+
+void reply_ulogoffX(struct smb_request *smb1req)
{
- struct smbd_server_connection *sconn = req->sconn;
- struct user_struct *vuser;
+ struct timeval now = timeval_current();
struct smbXsrv_session *session = NULL;
+ struct tevent_req *req;
NTSTATUS status;
- START_PROFILE(SMBulogoffX);
+ /*
+ * Don't setup the profile charge here, take
+ * it in reply_ulogoffX_done(). Not strictly correct
+ * but better than the other SMB1 async
+ * code that double-charges at the moment.
+ */
- vuser = get_valid_user_struct(sconn, req->vuid);
+ status = smb1srv_session_lookup(smb1req->xconn,
+ smb1req->vuid,
+ timeval_to_nttime(&now),
+ &session);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Not going async, profile here. */
+ START_PROFILE(SMBulogoffX);
+ DBG_WARNING("ulogoff, vuser id %llu does not map to user.\n",
+ (unsigned long long)smb1req->vuid);
- if(vuser == NULL) {
- DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
- (unsigned long long)req->vuid));
+ smb1req->vuid = UID_FIELD_INVALID;
+ reply_force_doserror(smb1req, ERRSRV, ERRbaduid);
+ END_PROFILE(SMBulogoffX);
+ return;
+ }
- req->vuid = UID_FIELD_INVALID;
- reply_force_doserror(req, ERRSRV, ERRbaduid);
+ req = reply_ulogoffX_send(smb1req, session);
+ if (req == NULL) {
+ /* Not going async, profile here. */
+ START_PROFILE(SMBulogoffX);
+ reply_force_doserror(smb1req, ERRDOS, ERRnomem);
END_PROFILE(SMBulogoffX);
return;
}
- session = vuser->session;
- vuser = NULL;
+ /* We're async. This will complete later. */
+ tevent_req_set_callback(req, reply_ulogoffX_done, smb1req);
+ return;
+}
+
+struct reply_ulogoffX_state {
+ struct tevent_queue *wait_queue;
+ struct smbXsrv_session *session;
+};
+
+static void reply_ulogoffX_wait_done(struct tevent_req *subreq);
+
+/****************************************************************************
+ Async SMB1 ulogoffX.
+ Note, on failure here we deallocate and return NULL to allow the caller to
+ SMB1 return an error of ERRnomem immediately.
+****************************************************************************/
+
+static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
+ struct smbXsrv_session *session)
+{
+ struct tevent_req *req;
+ struct reply_ulogoffX_state *state;
+ struct tevent_req *subreq;
+ files_struct *fsp;
+ struct smbd_server_connection *sconn = session->client->sconn;
+ uint64_t vuid = session->global->session_wire_id;
+
+ req = tevent_req_create(smb1req, &state,
+ struct reply_ulogoffX_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->wait_queue = tevent_queue_create(state,
+ "reply_ulogoffX_wait_queue");
+ if (tevent_req_nomem(state->wait_queue, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ state->session = session;
/*
- * TODO: cancel all outstanding requests on the session
+ * Make sure that no new request will be able to use this session.
+ * This ensures that once all outstanding fsp->aio_requests
+ * on this session are done, we are safe to close it.
*/
- status = smbXsrv_session_logoff(session);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("reply_ulogoff: "
- "smbXsrv_session_logoff() failed: %s\n",
- nt_errstr(status)));
+ session->status = NT_STATUS_USER_SESSION_DELETED;
+
+ for (fsp = sconn->files; fsp; fsp = fsp->next) {
+ if (fsp->vuid != vuid) {
+ continue;
+ }
/*
- * If we hit this case, there is something completely
- * wrong, so we better disconnect the transport connection.
+ * Flag the file as close in progress.
+ * This will prevent any more IO being
+ * done on it.
*/
+ fsp->closing = true;
+
+ if (fsp->num_aio_requests > 0) {
+ /*
+ * Now wait until all aio requests on this fsp are
+ * finished.
+ *
+ * We don't set a callback, as we just want to block the
+ * wait queue and the talloc_free() of fsp->aio_request
+ * will remove the item from the wait queue.
+ */
+ subreq = tevent_queue_wait_send(fsp->aio_requests,
+ sconn->ev_ctx,
+ state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ * Now we add our own waiter to the end of the queue,
+ * this way we get notified when all pending requests are finished
+ * and reply to the outstanding SMB1 request.
+ */
+ subreq = tevent_queue_wait_send(state,
+ sconn->ev_ctx,
+ state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ /*
+ * We're really going async - move the SMB1 request from
+ * a talloc stackframe above us to the sconn talloc-context.
+ * We need this to stick around until the wait_done
+ * callback is invoked.
+ */
+ smb1req = talloc_move(sconn, &smb1req);
+
+ tevent_req_set_callback(subreq, reply_ulogoffX_wait_done, req);
+
+ return req;
+}
+
+static void reply_ulogoffX_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+
+ tevent_queue_wait_recv(subreq);
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static NTSTATUS reply_ulogoffX_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static void reply_ulogoffX_done(struct tevent_req *req)
+{
+ struct smb_request *smb1req = tevent_req_callback_data(
+ req, struct smb_request);
+ struct reply_ulogoffX_state *state = tevent_req_data(req,
+ struct reply_ulogoffX_state);
+ struct smbXsrv_session *session = state->session;
+ NTSTATUS status;
+
+ /*
+ * Take the profile charge here. Not strictly
+ * correct but better than the other SMB1 async
+ * code that double-charges at the moment.
+ */
+ START_PROFILE(SMBulogoffX);
+
+ status = reply_ulogoffX_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb1req);
+ END_PROFILE(SMBulogoffX);
+ exit_server(__location__ ": reply_ulogoffX_recv failed");
+ return;
+ }
+
+ status = smbXsrv_session_logoff(session);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb1req);
END_PROFILE(SMBulogoffX);
exit_server(__location__ ": smbXsrv_session_logoff failed");
return;
TALLOC_FREE(session);
- reply_outbuf(req, 2, 0);
- SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
- SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
+ reply_outbuf(smb1req, 2, 0);
+ SSVAL(smb1req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+ SSVAL(smb1req->outbuf, smb_vwv1, 0); /* no andx offset */
- DEBUG(3, ("ulogoffX vuid=%llu\n",
- (unsigned long long)req->vuid));
+ DBG_NOTICE("ulogoffX vuid=%llu\n",
+ (unsigned long long)smb1req->vuid);
+ smb1req->vuid = UID_FIELD_INVALID;
+ /*
+ * The following call is needed to push the
+ * reply data back out the socket after async
+ * return. Plus it frees smb1req.
+ */
+ smb_request_done(smb1req);
END_PROFILE(SMBulogoffX);
- req->vuid = UID_FIELD_INVALID;
}
/****************************************************************************
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBcreate);
- ZERO_STRUCT(ft);
+ init_smb_file_time(&ft);
if (req->wct < 3) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
}
/* mtime. */
- ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
+ ft.mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+1));
srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
STR_TERMINATE, &status);
/* We have re-scheduled this call. */
goto out;
}
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ }
reply_openerror(req, status);
goto out;
}
/* We have re-scheduled this call. */
goto out;
}
+ if (NT_STATUS_EQUAL(
+ status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ }
reply_openerror(req, status);
goto out;
}
NTSTATUS status;
int ret;
bool posix_paths = (req != NULL && req->posix_pathnames);
+ struct smb2_create_blobs *posx = NULL;
DEBUG(10,("do_unlink: %s, dirtype = %d\n",
smb_fname_str_dbg(smb_fname),
return NT_STATUS_OBJECT_NAME_INVALID;
#endif /* JRATEST */
+ if (posix_paths) {
+ status = make_smb2_posix_create_ctx(
+ talloc_tos(), &posx, 0777);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ }
+
/* On open checks the open itself will check the share mode, so
don't do it here as we'll get it wrong. */
FILE_SHARE_NONE, /* share_access */
FILE_OPEN, /* create_disposition*/
FILE_NON_DIRECTORY_FILE, /* create_options */
- /* file_attributes */
- posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
- FILE_ATTRIBUTE_NORMAL,
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes */
0, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
NULL, /* ea_list */
&fsp, /* result */
NULL, /* pinfo */
- NULL, NULL); /* create context */
+ posx, /* in_context_blobs */
+ NULL); /* out_context_blobs */
+
+ TALLOC_FREE(posx);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
/* We have re-scheduled this call. */
goto out;
}
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ }
reply_nterror(req, status);
goto out;
}
smbd_unlock_socket(xconn);
}
+/*******************************************************************
+ Ensure we don't use sendfile if server smb signing is active.
+********************************************************************/
+
+static bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state)
+{
+ bool sign_active = false;
+
+ /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
+ if (get_Protocol() < PROTOCOL_NT1) {
+ return false;
+ }
+ if (signing_state) {
+ sign_active = smb_signing_is_active(signing_state);
+ }
+ return (lp__use_sendfile(snum) &&
+ (get_remote_arch() != RA_WIN95) &&
+ !sign_active);
+}
/****************************************************************************
Use sendfile in readbraw.
****************************************************************************/
*/
if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
- (fsp->wcp == NULL) &&
lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
ssize_t sendfile_read = -1;
char header[4];
files_struct *fsp;
struct lock_struct lock;
off_t size = 0;
+ NTSTATUS status;
START_PROFILE(SMBreadbraw);
return;
}
- flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
-
startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
if(req->wct == 10) {
/*
return;
}
- if (fsp_stat(fsp) == 0) {
+ status = vfs_stat_fsp(fsp);
+ if (NT_STATUS_IS_OK(status)) {
size = fsp->fsp_name->st.st_ex_size;
}
Reply to a lockread (core+ protocol).
****************************************************************************/
+static void reply_lockread_locked(struct tevent_req *subreq);
+
void reply_lockread(struct smb_request *req)
{
+ struct tevent_req *subreq = NULL;
connection_struct *conn = req->conn;
- ssize_t nread = -1;
- char *data;
- off_t startpos;
- size_t numtoread;
- size_t maxtoread;
- NTSTATUS status;
files_struct *fsp;
- struct byte_range_lock *br_lck = NULL;
- char *p = NULL;
- struct smbXsrv_connection *xconn = req->xconn;
+ struct smbd_lock_element *lck = NULL;
START_PROFILE(SMBlockread);
return;
}
- numtoread = SVAL(req->vwv+1, 0);
- startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
+ lck = talloc(req, struct smbd_lock_element);
+ if (lck == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBlockread);
+ return;
+ }
/*
* NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
* Note that the requested lock size is unaffected by max_send.
*/
- br_lck = do_lock(req->sconn->msg_ctx,
- fsp,
- (uint64_t)req->smbpid,
- (uint64_t)numtoread,
- (uint64_t)startpos,
- WRITE_LOCK,
- WINDOWS_LOCK,
- False, /* Non-blocking lock. */
- &status,
- NULL);
- TALLOC_FREE(br_lck);
+ *lck = (struct smbd_lock_element) {
+ .req_guid = smbd_request_guid(req, 0),
+ .smblctx = req->smbpid,
+ .brltype = WRITE_LOCK,
+ .count = SVAL(req->vwv+1, 0),
+ .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
+ };
- if (NT_STATUS_V(status)) {
- reply_nterror(req, status);
+ subreq = smbd_smb1_do_locks_send(
+ fsp,
+ req->sconn->ev_ctx,
+ &req,
+ fsp,
+ 0,
+ false, /* large_offset */
+ WINDOWS_LOCK,
+ 1,
+ lck);
+ if (subreq == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBlockread);
return;
}
+ tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
+ END_PROFILE(SMBlockread);
+}
+
+static void reply_lockread_locked(struct tevent_req *subreq)
+{
+ struct smb_request *req = NULL;
+ ssize_t nread = -1;
+ char *data = NULL;
+ NTSTATUS status;
+ bool ok;
+ off_t startpos;
+ size_t numtoread, maxtoread;
+ struct files_struct *fsp = NULL;
+ char *p = NULL;
+
+ START_PROFILE(SMBlockread);
+
+ ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
+ SMB_ASSERT(ok);
+
+ status = smbd_smb1_do_locks_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ goto send;
+ }
+
+ fsp = file_fsp(req, SVAL(req->vwv+0, 0));
+ if (fsp == NULL) {
+ reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ goto send;
+ }
+
+ numtoread = SVAL(req->vwv+1, 0);
+ startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
/*
* However the requested READ size IS affected by max_send. Insanity.... JRA.
*/
- maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
+ maxtoread = req->xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
if (numtoread > maxtoread) {
- DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
-Returning short read of maximum allowed for compatibility with Windows 2000.\n",
- (unsigned int)numtoread, (unsigned int)maxtoread,
- (unsigned int)xconn->smb1.sessions.max_send));
+ DBG_WARNING("requested read size (%zu) is greater than "
+ "maximum allowed (%zu/%d). "
+ "Returning short read of maximum allowed for "
+ "compatibility with Windows 2000.\n",
+ numtoread,
+ maxtoread,
+ req->xconn->smb1.sessions.max_send);
numtoread = maxtoread;
}
if (nread < 0) {
reply_nterror(req, map_nt_error_from_unix(errno));
- END_PROFILE(SMBlockread);
- return;
+ goto send;
}
srv_set_message((char *)req->outbuf, 5, nread+3, False);
DEBUG(3,("lockread %s num=%d nread=%d\n",
fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
+send:
+ ok = srv_send_smb(req->xconn,
+ (char *)req->outbuf,
+ true,
+ req->seqnum+1,
+ IS_CONN_ENCRYPTED(req->conn),
+ NULL);
+ if (!ok) {
+ exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
+ }
+ TALLOC_FREE(req);
END_PROFILE(SMBlockread);
return;
}
ssize_t nread = -1;
struct lock_struct lock;
int saved_errno = 0;
+ NTSTATUS status;
init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
(uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
if (!req_is_in_chain(req) &&
!req->encrypted &&
(fsp->base_fsp == NULL) &&
- (fsp->wcp == NULL) &&
lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
DATA_BLOB header;
- if(fsp_stat(fsp) == -1) {
- reply_nterror(req, map_nt_error_from_unix(errno));
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
goto out;
}
}
if (numtowrite && !fsp->print_file) {
- status = do_unlock(req->sconn->msg_ctx,
- fsp,
- (uint64_t)req->smbpid,
- (uint64_t)numtowrite,
- (uint64_t)startpos,
- WINDOWS_LOCK);
-
+ struct smbd_lock_element l = {
+ .req_guid = smbd_request_guid(req, 0),
+ .smblctx = req->smbpid,
+ .brltype = UNLOCK_LOCK,
+ .offset = startpos,
+ .count = numtowrite,
+ };
+ status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
if (NT_STATUS_V(status)) {
reply_nterror(req, status);
goto out;
off_t res= -1;
int mode,umode;
files_struct *fsp;
+ NTSTATUS status;
START_PROFILE(SMBlseek);
return;
}
- flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
-
mode = SVAL(req->vwv+1, 0) & 3;
/* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
startpos = (off_t)IVALS(req->vwv+2, 0);
if(errno == EINVAL) {
off_t current_pos = startpos;
- if(fsp_stat(fsp) == -1) {
- reply_nterror(req,
- map_nt_error_from_unix(errno));
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
END_PROFILE(SMBlseek);
return;
}
return;
}
-struct reply_close_state {
- files_struct *fsp;
- struct smb_request *smbreq;
+#if 0
+struct reply_exit_state {
+ struct tevent_queue *wait_queue;
};
-static void do_smb1_close(struct tevent_req *req);
+static void reply_exit_wait_done(struct tevent_req *subreq);
-void reply_close(struct smb_request *req)
+/****************************************************************************
+ Async SMB1 exit.
+ Note, on failure here we deallocate and return NULL to allow the caller to
+ SMB1 return an error of ERRnomem immediately.
+****************************************************************************/
+
+static struct tevent_req *reply_exit_send(struct smb_request *smb1req)
{
- connection_struct *conn = req->conn;
- NTSTATUS status = NT_STATUS_OK;
- files_struct *fsp = NULL;
+ struct tevent_req *req;
+ struct reply_exit_state *state;
+ struct tevent_req *subreq;
+ files_struct *fsp;
+ struct smbd_server_connection *sconn = smb1req->sconn;
+
+ req = tevent_req_create(smb1req, &state,
+ struct reply_exit_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->wait_queue = tevent_queue_create(state,
+ "reply_exit_wait_queue");
+ if (tevent_req_nomem(state->wait_queue, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ for (fsp = sconn->files; fsp; fsp = fsp->next) {
+ if (fsp->file_pid != smb1req->smbpid) {
+ continue;
+ }
+ if (fsp->vuid != smb1req->vuid) {
+ continue;
+ }
+ /*
+ * Flag the file as close in progress.
+ * This will prevent any more IO being
+ * done on it.
+ */
+ fsp->closing = true;
+
+ if (fsp->num_aio_requests > 0) {
+ /*
+ * Now wait until all aio requests on this fsp are
+ * finished.
+ *
+ * We don't set a callback, as we just want to block the
+ * wait queue and the talloc_free() of fsp->aio_request
+ * will remove the item from the wait queue.
+ */
+ subreq = tevent_queue_wait_send(fsp->aio_requests,
+ sconn->ev_ctx,
+ state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ * Now we add our own waiter to the end of the queue,
+ * this way we get notified when all pending requests are finished
+ * and reply to the outstanding SMB1 request.
+ */
+ subreq = tevent_queue_wait_send(state,
+ sconn->ev_ctx,
+ state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ /*
+ * We're really going async - move the SMB1 request from
+ * a talloc stackframe above us to the conn talloc-context.
+ * We need this to stick around until the wait_done
+ * callback is invoked.
+ */
+ smb1req = talloc_move(sconn, &smb1req);
+
+ tevent_req_set_callback(subreq, reply_exit_wait_done, req);
+
+ return req;
+}
+
+static void reply_exit_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+
+ tevent_queue_wait_recv(subreq);
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static NTSTATUS reply_exit_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static void reply_exit_done(struct tevent_req *req)
+{
+ struct smb_request *smb1req = tevent_req_callback_data(
+ req, struct smb_request);
+ struct smbd_server_connection *sconn = smb1req->sconn;
+ struct smbXsrv_connection *xconn = smb1req->xconn;
+ NTTIME now = timeval_to_nttime(&smb1req->request_time);
+ struct smbXsrv_session *session = NULL;
+ files_struct *fsp, *next;
+ NTSTATUS status;
+
+ /*
+ * Take the profile charge here. Not strictly
+ * correct but better than the other SMB1 async
+ * code that double-charges at the moment.
+ */
+ START_PROFILE(SMBexit);
+
+ status = reply_exit_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb1req);
+ END_PROFILE(SMBexit);
+ exit_server(__location__ ": reply_exit_recv failed");
+ return;
+ }
+
+ /*
+ * Ensure the session is still valid.
+ */
+ status = smb1srv_session_lookup(xconn,
+ smb1req->vuid,
+ now,
+ &session);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
+ smb_request_done(smb1req);
+ END_PROFILE(SMBexit);
+ }
+
+ /*
+ * Ensure the vuid is still valid - no one
+ * called reply_ulogoffX() in the meantime.
+ * reply_exit() doesn't have AS_USER set, so
+ * use set_current_user_info() directly.
+ * This is the same logic as in switch_message().
+ */
+ if (session->global->auth_session_info != NULL) {
+ set_current_user_info(
+ session->global->auth_session_info->unix_info->sanitized_username,
+ session->global->auth_session_info->unix_info->unix_name,
+ session->global->auth_session_info->info->domain_name);
+ }
+
+ /* No more aio - do the actual closes. */
+ for (fsp = sconn->files; fsp; fsp = next) {
+ bool ok;
+ next = fsp->next;
+
+ if (fsp->file_pid != smb1req->smbpid) {
+ continue;
+ }
+ if (fsp->vuid != smb1req->vuid) {
+ continue;
+ }
+ if (!fsp->closing) {
+ continue;
+ }
+
+ /*
+ * reply_exit() has the DO_CHDIR flag set.
+ */
+ ok = chdir_current_service(fsp->conn);
+ if (!ok) {
+ reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
+ smb_request_done(smb1req);
+ END_PROFILE(SMBexit);
+ }
+ close_file(NULL, fsp, SHUTDOWN_CLOSE);
+ }
+
+ reply_outbuf(smb1req, 0, 0);
+ /*
+ * The following call is needed to push the
+ * reply data back out the socket after async
+ * return. Plus it frees smb1req.
+ */
+ smb_request_done(smb1req);
+ DBG_INFO("reply_exit complete\n");
+ END_PROFILE(SMBexit);
+ return;
+}
+#endif
+
+struct reply_close_state {
+ files_struct *fsp;
+ struct smb_request *smbreq;
+};
+
+static void do_smb1_close(struct tevent_req *req);
+
+void reply_close(struct smb_request *req)
+{
+ connection_struct *conn = req->conn;
+ NTSTATUS status = NT_STATUS_OK;
+ files_struct *fsp = NULL;
START_PROFILE(SMBclose);
if (req->wct < 3) {
*/
t = srv_make_unix_date3(req->vwv+1);
- set_close_write_time(fsp, convert_time_t_to_timespec(t));
+ set_close_write_time(fsp, time_t_to_full_timespec(t));
}
if (fsp->num_aio_requests != 0) {
DEBUG(10, ("closing with aio %u requests pending\n",
fsp->num_aio_requests));
+ /*
+ * Flag the file as close in progress.
+ * This will prevent any more IO being
+ * done on it.
+ */
+ fsp->closing = true;
+
/*
* We depend on the aio_extra destructor to take care of this
* close request once fsp->num_aio_request drops to 0.
numtowrite = SVAL(req->vwv+1, 0);
startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
- mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
+ mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+4));
data = (const char *)req->buf + 1;
/*
Reply to a lock.
****************************************************************************/
+static void reply_lock_done(struct tevent_req *subreq);
+
void reply_lock(struct smb_request *req)
{
+ struct tevent_req *subreq = NULL;
connection_struct *conn = req->conn;
- uint64_t count,offset;
- NTSTATUS status;
files_struct *fsp;
- struct byte_range_lock *br_lck = NULL;
+ struct smbd_lock_element *lck = NULL;
START_PROFILE(SMBlock);
return;
}
- count = (uint64_t)IVAL(req->vwv+1, 0);
- offset = (uint64_t)IVAL(req->vwv+3, 0);
-
- DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
- fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
-
- br_lck = do_lock(req->sconn->msg_ctx,
- fsp,
- (uint64_t)req->smbpid,
- count,
- offset,
- WRITE_LOCK,
- WINDOWS_LOCK,
- False, /* Non-blocking lock. */
- &status,
- NULL);
+ lck = talloc(req, struct smbd_lock_element);
+ if (lck == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBlock);
+ return;
+ }
- TALLOC_FREE(br_lck);
+ *lck = (struct smbd_lock_element) {
+ .req_guid = smbd_request_guid(req, 0),
+ .smblctx = req->smbpid,
+ .brltype = WRITE_LOCK,
+ .count = IVAL(req->vwv+1, 0),
+ .offset = IVAL(req->vwv+3, 0),
+ };
- if (NT_STATUS_V(status)) {
- reply_nterror(req, status);
+ DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
+ fsp->fh->fd,
+ fsp_fnum_dbg(fsp),
+ lck->offset,
+ lck->count);
+
+ subreq = smbd_smb1_do_locks_send(
+ fsp,
+ req->sconn->ev_ctx,
+ &req,
+ fsp,
+ 0,
+ false, /* large_offset */
+ WINDOWS_LOCK,
+ 1,
+ lck);
+ if (subreq == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBlock);
return;
}
+ tevent_req_set_callback(subreq, reply_lock_done, NULL);
+ END_PROFILE(SMBlock);
+}
- reply_outbuf(req, 0, 0);
+static void reply_lock_done(struct tevent_req *subreq)
+{
+ struct smb_request *req = NULL;
+ NTSTATUS status;
+ bool ok;
+ START_PROFILE(SMBlock);
+
+ ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
+ SMB_ASSERT(ok);
+
+ status = smbd_smb1_do_locks_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_IS_OK(status)) {
+ reply_outbuf(req, 0, 0);
+ } else {
+ reply_nterror(req, status);
+ }
+
+ ok = srv_send_smb(req->xconn,
+ (char *)req->outbuf,
+ true,
+ req->seqnum+1,
+ IS_CONN_ENCRYPTED(req->conn),
+ NULL);
+ if (!ok) {
+ exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
+ }
+ TALLOC_FREE(req);
END_PROFILE(SMBlock);
- return;
}
/****************************************************************************
void reply_unlock(struct smb_request *req)
{
connection_struct *conn = req->conn;
- uint64_t count,offset;
NTSTATUS status;
files_struct *fsp;
+ struct smbd_lock_element lck;
START_PROFILE(SMBunlock);
return;
}
- count = (uint64_t)IVAL(req->vwv+1, 0);
- offset = (uint64_t)IVAL(req->vwv+3, 0);
+ lck = (struct smbd_lock_element) {
+ .req_guid = smbd_request_guid(req, 0),
+ .smblctx = req->smbpid,
+ .brltype = UNLOCK_LOCK,
+ .offset = IVAL(req->vwv+3, 0),
+ .count = IVAL(req->vwv+1, 0),
+ };
- status = do_unlock(req->sconn->msg_ctx,
- fsp,
- (uint64_t)req->smbpid,
- count,
- offset,
- WINDOWS_LOCK);
+ status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
- if (NT_STATUS_V(status)) {
+ if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
END_PROFILE(SMBunlock);
return;
}
- DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
- fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
+ DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
+ fsp->fh->fd,
+ fsp_fnum_dbg(fsp),
+ lck.offset,
+ lck.count);
reply_outbuf(req, 0, 0);
conn POINTER CAN BE NULL HERE !
****************************************************************************/
-void reply_tdis(struct smb_request *req)
+static struct tevent_req *reply_tdis_send(struct smb_request *smb1req);
+static void reply_tdis_done(struct tevent_req *req);
+
+void reply_tdis(struct smb_request *smb1req)
{
- NTSTATUS status;
- connection_struct *conn = req->conn;
- struct smbXsrv_tcon *tcon;
+ connection_struct *conn = smb1req->conn;
+ struct tevent_req *req;
- START_PROFILE(SMBtdis);
+ /*
+ * Don't setup the profile charge here, take
+ * it in reply_tdis_done(). Not strictly correct
+ * but better than the other SMB1 async
+ * code that double-charges at the moment.
+ */
- if (!conn) {
- DEBUG(4,("Invalid connection in tdis\n"));
- reply_force_doserror(req, ERRSRV, ERRinvnid);
+ if (conn == NULL) {
+ /* Not going async, profile here. */
+ START_PROFILE(SMBtdis);
+ DBG_INFO("Invalid connection in tdis\n");
+ reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
END_PROFILE(SMBtdis);
return;
}
- tcon = conn->tcon;
- req->conn = NULL;
+ req = reply_tdis_send(smb1req);
+ if (req == NULL) {
+ /* Not going async, profile here. */
+ START_PROFILE(SMBtdis);
+ reply_force_doserror(smb1req, ERRDOS, ERRnomem);
+ END_PROFILE(SMBtdis);
+ return;
+ }
+ /* We're async. This will complete later. */
+ tevent_req_set_callback(req, reply_tdis_done, smb1req);
+ return;
+}
+
+struct reply_tdis_state {
+ struct tevent_queue *wait_queue;
+};
+
+static void reply_tdis_wait_done(struct tevent_req *subreq);
+
+/****************************************************************************
+ Async SMB1 tdis.
+ Note, on failure here we deallocate and return NULL to allow the caller to
+ SMB1 return an error of ERRnomem immediately.
+****************************************************************************/
+
+static struct tevent_req *reply_tdis_send(struct smb_request *smb1req)
+{
+ struct tevent_req *req;
+ struct reply_tdis_state *state;
+ struct tevent_req *subreq;
+ connection_struct *conn = smb1req->conn;
+ files_struct *fsp;
+
+ req = tevent_req_create(smb1req, &state,
+ struct reply_tdis_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->wait_queue = tevent_queue_create(state, "reply_tdis_wait_queue");
+ if (tevent_req_nomem(state->wait_queue, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
/*
- * TODO: cancel all outstanding requests on the tcon
+ * Make sure that no new request will be able to use this tcon.
+ * This ensures that once all outstanding fsp->aio_requests
+ * on this tcon are done, we are safe to close it.
*/
- status = smbXsrv_tcon_disconnect(tcon, req->vuid);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("reply_tdis: "
- "smbXsrv_tcon_disconnect() failed: %s\n",
- nt_errstr(status)));
+ conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
+
+ for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
+ if (fsp->conn != conn) {
+ continue;
+ }
/*
- * If we hit this case, there is something completely
- * wrong, so we better disconnect the transport connection.
+ * Flag the file as close in progress.
+ * This will prevent any more IO being
+ * done on it. Not strictly needed, but
+ * doesn't hurt to flag it as closing.
*/
+ fsp->closing = true;
+
+ if (fsp->num_aio_requests > 0) {
+ /*
+ * Now wait until all aio requests on this fsp are
+ * finished.
+ *
+ * We don't set a callback, as we just want to block the
+ * wait queue and the talloc_free() of fsp->aio_request
+ * will remove the item from the wait queue.
+ */
+ subreq = tevent_queue_wait_send(fsp->aio_requests,
+ conn->sconn->ev_ctx,
+ state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ * Now we add our own waiter to the end of the queue,
+ * this way we get notified when all pending requests are finished
+ * and reply to the outstanding SMB1 request.
+ */
+ subreq = tevent_queue_wait_send(state,
+ conn->sconn->ev_ctx,
+ state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ /*
+ * We're really going async - move the SMB1 request from
+ * a talloc stackframe above us to the sconn talloc-context.
+ * We need this to stick around until the wait_done
+ * callback is invoked.
+ */
+ smb1req = talloc_move(smb1req->sconn, &smb1req);
+
+ tevent_req_set_callback(subreq, reply_tdis_wait_done, req);
+
+ return req;
+}
+
+static void reply_tdis_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+
+ tevent_queue_wait_recv(subreq);
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static NTSTATUS reply_tdis_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static void reply_tdis_done(struct tevent_req *req)
+{
+ struct smb_request *smb1req = tevent_req_callback_data(
+ req, struct smb_request);
+ NTSTATUS status;
+ struct smbXsrv_tcon *tcon = smb1req->conn->tcon;
+ bool ok;
+
+ /*
+ * Take the profile charge here. Not strictly
+ * correct but better than the other SMB1 async
+ * code that double-charges at the moment.
+ */
+ START_PROFILE(SMBtdis);
+
+ status = reply_tdis_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb1req);
+ END_PROFILE(SMBtdis);
+ exit_server(__location__ ": reply_tdis_recv failed");
+ return;
+ }
+
+ /*
+ * As we've been awoken, we may have changed
+ * directory in the meantime.
+ * reply_tdis() has the DO_CHDIR flag set.
+ */
+ ok = chdir_current_service(smb1req->conn);
+ if (!ok) {
+ reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
+ smb_request_done(smb1req);
+ END_PROFILE(SMBtdis);
+ }
+
+ status = smbXsrv_tcon_disconnect(tcon,
+ smb1req->vuid);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb1req);
END_PROFILE(SMBtdis);
exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
return;
}
+ /* smbXsrv_tcon_disconnect frees smb1req->conn. */
+ smb1req->conn = NULL;
+
TALLOC_FREE(tcon);
- reply_outbuf(req, 0, 0);
+ reply_outbuf(smb1req, 0, 0);
+ /*
+ * The following call is needed to push the
+ * reply data back out the socket after async
+ * return. Plus it frees smb1req.
+ */
+ smb_request_done(smb1req);
END_PROFILE(SMBtdis);
- return;
}
/****************************************************************************
void reply_printqueue(struct smb_request *req)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
connection_struct *conn = req->conn;
int max_count;
int start_index;
TALLOC_CTX *mem_ctx = talloc_tos();
NTSTATUS status;
WERROR werr;
- const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
+ const char *sharename = lp_servicename(mem_ctx, lp_sub, SNUM(conn));
struct rpc_pipe_client *cli = NULL;
struct dcerpc_binding_handle *b = NULL;
struct policy_handle handle;
files_struct *fsp = NULL;
int info = 0;
uint32_t ucf_flags = ucf_flags_from_smb_request(req);
- struct smbd_server_connection *sconn = req->sconn;
START_PROFILE(SMBrmdir);
/* We have re-scheduled this call. */
goto out;
}
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ }
reply_nterror(req, status);
goto out;
}
reply_outbuf(req, 0, 0);
}
- dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
-
DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
out:
TALLOC_FREE(smb_dname);
for(fsp = file_find_di_first(conn->sconn, id); fsp;
fsp = file_find_di_next(fsp)) {
+ struct file_id_buf idbuf;
/* fsp_name is a relative path under the fsp. To change this for other
sharepaths we need to manipulate relative paths. */
/* TODO - create the absolute path and manipulate the newname
if (fsp->name_hash != orig_name_hash) {
continue;
}
- DEBUG(10, ("rename_open_files: renaming file %s "
- "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
- file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
- smb_fname_str_dbg(smb_fname_dst)));
+ DBG_DEBUG("renaming file %s "
+ "(file_id %s) from %s -> %s\n",
+ fsp_fnum_dbg(fsp),
+ file_id_str_buf(fsp->file_id, &idbuf),
+ fsp_str_dbg(fsp),
+ smb_fname_str_dbg(smb_fname_dst));
status = fsp_set_smb_fname(fsp, smb_fname_dst);
if (NT_STATUS_IS_OK(status)) {
}
if (!did_rename) {
- DEBUG(10, ("rename_open_files: no open files on file_id %s "
- "for %s\n", file_id_string_tos(&id),
- smb_fname_str_dbg(smb_fname_dst)));
+ struct file_id_buf idbuf;
+ DBG_DEBUG("no open files on file_id %s "
+ "for %s\n",
+ file_id_str_buf(id, &idbuf),
+ smb_fname_str_dbg(smb_fname_dst));
}
/* Send messages to all smbd's (not ourself) that the name has changed. */
struct share_mode_lock *lck = NULL;
uint32_t access_mask = SEC_DIR_ADD_FILE;
bool dst_exists, old_is_stream, new_is_stream;
+ int ret;
status = check_name(conn, smb_fname_dst_in);
if (!NT_STATUS_IS_OK(status)) {
SMB_ASSERT(lck != NULL);
- if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
+ ret = SMB_VFS_RENAMEAT(conn,
+ conn->cwd_fsp,
+ fsp->fsp_name,
+ conn->cwd_fsp,
+ smb_fname_dst);
+ if (ret == 0) {
uint32_t create_options = fsp->fh->private_options;
DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
long offset = 0;
int create_options = 0;
bool posix_pathnames = (req != NULL && req->posix_pathnames);
+ struct smb2_create_blobs *posx = NULL;
int rc;
/*
}
}
+ if (posix_pathnames) {
+ status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+ nt_errstr(status));
+ goto out;
+ }
+ }
+
if (!src_has_wild) {
files_struct *fsp;
FILE_SHARE_WRITE),
FILE_OPEN, /* create_disposition*/
create_options, /* create_options */
- posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
+ 0, /* file_attributes */
0, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
NULL, /* ea_list */
&fsp, /* result */
NULL, /* pinfo */
- NULL, NULL); /* create context */
+ posx, /* in_context_blobs */
+ NULL); /* out_context_blobs */
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("Could not open rename source %s: %s\n",
FILE_SHARE_WRITE),
FILE_OPEN, /* create_disposition*/
create_options, /* create_options */
- posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
+ 0, /* file_attributes */
0, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
NULL, /* ea_list */
&fsp, /* result */
NULL, /* pinfo */
- NULL, NULL); /* create context */
+ posx, /* in_context_blobs */
+ NULL); /* out_context_blobs */
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
}
out:
+ TALLOC_FREE(posx);
TALLOC_FREE(talloced);
TALLOC_FREE(smb_fname_src_dir);
TALLOC_FREE(fname_src_dir);
/* We have re-scheduled this call. */
goto out;
}
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ }
reply_nterror(req, status);
goto out;
}
return offset;
}
-NTSTATUS smbd_do_locking(struct smb_request *req,
- files_struct *fsp,
- uint8_t type,
- int32_t timeout,
- uint16_t num_locks,
- struct smbd_lock_element *locks,
- bool *async)
-{
- connection_struct *conn = req->conn;
- int i;
- NTSTATUS status = NT_STATUS_OK;
-
- *async = false;
-
- /* Setup the timeout in seconds. */
+struct smbd_do_unlocking_state {
+ struct files_struct *fsp;
+ uint16_t num_ulocks;
+ struct smbd_lock_element *ulocks;
+ enum brl_flavour lock_flav;
+ NTSTATUS status;
+};
- if (!lp_blocking_locks(SNUM(conn))) {
- timeout = 0;
- }
+static void smbd_do_unlocking_fn(
+ TDB_DATA value, bool *pmodified_dependent, void *private_data)
+{
+ struct smbd_do_unlocking_state *state = private_data;
+ struct files_struct *fsp = state->fsp;
+ enum brl_flavour lock_flav = state->lock_flav;
+ uint16_t i;
- for(i = 0; i < (int)num_locks; i++) {
- struct smbd_lock_element *e = &locks[i];
+ for (i = 0; i < state->num_ulocks; i++) {
+ struct smbd_lock_element *e = &state->ulocks[i];
- DBG_DEBUG("lock start=%"PRIu64", len=%"PRIu64" for smblctx "
- "%"PRIu64", file %s timeout = %"PRIi32"\n",
+ DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
+ "pid %"PRIu64", file %s\n",
e->offset,
e->count,
e->smblctx,
- fsp_str_dbg(fsp),
- timeout);
-
- {
- bool blocking_lock = (timeout != 0);
- bool defer_lock = false;
- struct byte_range_lock *br_lck;
- uint64_t block_smblctx;
-
- br_lck = do_lock(req->sconn->msg_ctx,
- fsp,
- e->smblctx,
- e->count,
- e->offset,
- e->brltype,
- WINDOWS_LOCK,
- blocking_lock,
- &status,
- &block_smblctx);
-
- if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
- /* Windows internal resolution for blocking locks seems
- to be about 200ms... Don't wait for less than that. JRA. */
- if (timeout != -1) {
- timeout = MAX(timeout, lp_lock_spin_time());
- }
- defer_lock = true;
- }
-
- /* If a lock sent with timeout of zero would fail, and
- * this lock has been requested multiple times,
- * according to brl_lock_failed() we convert this
- * request to a blocking lock with a timeout of between
- * 150 - 300 milliseconds.
- *
- * If lp_lock_spin_time() has been set to 0, we skip
- * this blocking retry and fail immediately.
- *
- * Replacement for do_lock_spin(). JRA. */
-
- if (!req->sconn->using_smb2 &&
- br_lck && lp_blocking_locks(SNUM(conn)) &&
- lp_lock_spin_time() && !blocking_lock &&
- NT_STATUS_EQUAL((status),
- NT_STATUS_FILE_LOCK_CONFLICT))
- {
- defer_lock = true;
- timeout = lp_lock_spin_time();
- }
-
- if (br_lck && defer_lock) {
- /*
- * A blocking lock was requested. Package up
- * this smb into a queued request and push it
- * onto the blocking lock queue.
- */
- if(push_blocking_lock_request(br_lck,
- req,
- fsp,
- timeout,
- i,
- e->smblctx,
- e->brltype,
- WINDOWS_LOCK,
- e->offset,
- e->count,
- block_smblctx)) {
- TALLOC_FREE(br_lck);
- *async = true;
- return NT_STATUS_OK;
- }
- }
-
- TALLOC_FREE(br_lck);
- }
+ fsp_str_dbg(fsp));
- if (!NT_STATUS_IS_OK(status)) {
- break;
+ if (e->brltype != UNLOCK_LOCK) {
+ /* this can only happen with SMB2 */
+ state->status = NT_STATUS_INVALID_PARAMETER;
+ return;
}
- }
-
- /* If any of the above locks failed, then we must unlock
- all of the previous locks (X/Open spec). */
- if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
+ state->status = do_unlock(
+ fsp, e->smblctx, e->count, e->offset, lock_flav);
- /*
- * Ensure we don't do a remove on the lock that just failed,
- * as under POSIX rules, if we have a lock already there, we
- * will delete it (and we shouldn't) .....
- */
- for(i--; i >= 0; i--) {
- struct smbd_lock_element *e = &locks[i];
+ DBG_DEBUG("do_unlock returned %s\n",
+ nt_errstr(state->status));
- do_unlock(req->sconn->msg_ctx,
- fsp,
- e->smblctx,
- e->count,
- e->offset,
- WINDOWS_LOCK);
+ if (!NT_STATUS_IS_OK(state->status)) {
+ return;
}
- return status;
}
- DBG_NOTICE("%s type=%"PRIu8" num_locks=%"PRIu16"\n",
- fsp_fnum_dbg(fsp),
- type,
- num_locks);
-
- return NT_STATUS_OK;
+ *pmodified_dependent = true;
}
NTSTATUS smbd_do_unlocking(struct smb_request *req,
files_struct *fsp,
uint16_t num_ulocks,
- struct smbd_lock_element *ulocks)
+ struct smbd_lock_element *ulocks,
+ enum brl_flavour lock_flav)
{
- uint16_t i;
-
- for(i = 0; i < num_ulocks; i++) {
- struct smbd_lock_element *e = &ulocks[i];
- NTSTATUS status;
-
- DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
- "pid %"PRIu64", file %s\n",
- e->offset,
- e->count,
- e->smblctx,
- fsp_str_dbg(fsp));
-
- if (e->brltype != UNLOCK_LOCK) {
- /* this can only happen with SMB2 */
- return NT_STATUS_INVALID_PARAMETER;
- }
+ struct smbd_do_unlocking_state state = {
+ .fsp = fsp,
+ .num_ulocks = num_ulocks,
+ .ulocks = ulocks,
+ .lock_flav = lock_flav,
+ };
+ NTSTATUS status;
- status = do_unlock(req->sconn->msg_ctx,
- fsp,
- e->smblctx,
- e->count,
- e->offset,
- WINDOWS_LOCK);
+ DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
- DEBUG(10, ("%s: unlock returned %s\n", __func__,
- nt_errstr(status)));
+ status = share_mode_do_locked(
+ fsp->file_id, smbd_do_unlocking_fn, &state);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("share_mode_do_locked failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(state.status)) {
+ DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
+ nt_errstr(status));
+ return state.status;
}
-
- DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
- num_ulocks));
return NT_STATUS_OK;
}
Reply to a lockingX request.
****************************************************************************/
+static void reply_lockingx_done(struct tevent_req *subreq);
+
void reply_lockingX(struct smb_request *req)
{
connection_struct *conn = req->conn;
uint16_t num_ulocks;
uint16_t num_locks;
int32_t lock_timeout;
- int i;
+ uint16_t i;
const uint8_t *data;
bool large_file_format;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- struct smbd_lock_element *ulocks = NULL;
struct smbd_lock_element *locks = NULL;
- bool async = false;
+ struct tevent_req *subreq = NULL;
START_PROFILE(SMBlockingX);
return;
}
- ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
- if (ulocks == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- END_PROFILE(SMBlockingX);
- return;
- }
+ if (num_ulocks != 0) {
+ struct smbd_lock_element *ulocks = NULL;
+ bool ok;
- /* Data now points at the beginning of the list
- of smb_unlkrng structs */
- for(i = 0; i < (int)num_ulocks; i++) {
- ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
- ulocks[i].count = get_lock_count(data, i, large_file_format);
- ulocks[i].offset = get_lock_offset(data, i, large_file_format);
- ulocks[i].brltype = UNLOCK_LOCK;
- }
+ ulocks = talloc_array(
+ req, struct smbd_lock_element, num_ulocks);
+ if (ulocks == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBlockingX);
+ return;
+ }
- status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
- TALLOC_FREE(ulocks);
- if (!NT_STATUS_IS_OK(status)) {
- END_PROFILE(SMBlockingX);
- reply_nterror(req, status);
- return;
+ /*
+ * Data now points at the beginning of the list of
+ * smb_unlkrng structs
+ */
+ for (i = 0; i < num_ulocks; i++) {
+ ulocks[i].req_guid = smbd_request_guid(req,
+ UINT16_MAX - i),
+ ulocks[i].smblctx = get_lock_pid(
+ data, i, large_file_format);
+ ulocks[i].count = get_lock_count(
+ data, i, large_file_format);
+ ulocks[i].offset = get_lock_offset(
+ data, i, large_file_format);
+ ulocks[i].brltype = UNLOCK_LOCK;
+ }
+
+ /*
+ * Unlock cancels pending locks
+ */
+
+ ok = smbd_smb1_brl_finish_by_lock(
+ fsp,
+ large_file_format,
+ WINDOWS_LOCK,
+ ulocks[0],
+ NT_STATUS_OK);
+ if (ok) {
+ reply_outbuf(req, 2, 0);
+ SSVAL(req->outbuf, smb_vwv0, 0xff);
+ SSVAL(req->outbuf, smb_vwv1, 0);
+ END_PROFILE(SMBlockingX);
+ return;
+ }
+
+ status = smbd_do_unlocking(
+ req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
+ TALLOC_FREE(ulocks);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBlockingX);
+ reply_nterror(req, status);
+ return;
+ }
}
/* Now do any requested locks */
of smb_lkrng structs */
if (locktype & LOCKING_ANDX_SHARED_LOCK) {
- if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
- brltype = PENDING_READ_LOCK;
- } else {
- brltype = READ_LOCK;
- }
+ brltype = READ_LOCK;
} else {
- if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
- brltype = PENDING_WRITE_LOCK;
- } else {
- brltype = WRITE_LOCK;
- }
+ brltype = WRITE_LOCK;
}
locks = talloc_array(req, struct smbd_lock_element, num_locks);
return;
}
- for(i = 0; i < (int)num_locks; i++) {
+ for (i = 0; i < num_locks; i++) {
+ locks[i].req_guid = smbd_request_guid(req, i),
locks[i].smblctx = get_lock_pid(data, i, large_file_format);
locks[i].count = get_lock_count(data, i, large_file_format);
locks[i].offset = get_lock_offset(data, i, large_file_format);
}
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
- struct smbd_lock_element *e = NULL;
+
+ bool ok;
if (num_locks == 0) {
/* See smbtorture3 lock11 test */
- goto done;
+ reply_outbuf(req, 2, 0);
+ /* andx chain ends */
+ SSVAL(req->outbuf, smb_vwv0, 0xff);
+ SSVAL(req->outbuf, smb_vwv1, 0);
+ END_PROFILE(SMBlockingX);
+ return;
}
- e = &locks[0];
-
- /*
- * MS-CIFS (2.2.4.32.1) states that a cancel is
- * honored if and only if the lock vector contains one
- * entry. When given multiple cancel requests in a
- * single PDU we expect the server to return an
- * error. Windows servers seem to accept the request
- * but only cancel the first lock.
- *
- * JRA - Do what Windows does (tm) :-).
- */
+ ok = smbd_smb1_brl_finish_by_lock(
+ fsp,
+ large_file_format,
+ WINDOWS_LOCK,
+ locks[0], /* Windows only cancels the first lock */
+ NT_STATUS_FILE_LOCK_CONFLICT);
- if (lp_blocking_locks(SNUM(conn))) {
- struct blocking_lock_record *blr = NULL;
-
- /* Schedule a message to ourselves to
- remove the blocking lock record and
- return the right error. */
-
- blr = blocking_lock_cancel_smb1(
- fsp,
- e->smblctx,
- e->offset,
- e->count,
- WINDOWS_LOCK,
- locktype,
- NT_STATUS_FILE_LOCK_CONFLICT);
- if (blr == NULL) {
- reply_force_doserror(
- req, ERRDOS, ERRcancelviolation);
- END_PROFILE(SMBlockingX);
- return;
- }
+ if (!ok) {
+ reply_force_doserror(req, ERRDOS, ERRcancelviolation);
+ END_PROFILE(SMBlockingX);
+ return;
}
- /* Remove a matching pending lock. */
- status = do_lock_cancel(fsp,
- e->smblctx,
- e->count,
- e->offset,
- WINDOWS_LOCK);
+ reply_outbuf(req, 2, 0);
+ SSVAL(req->outbuf, smb_vwv0, 0xff);
+ SSVAL(req->outbuf, smb_vwv1, 0);
END_PROFILE(SMBlockingX);
- reply_nterror(req, status);
return;
}
- status = smbd_do_locking(req, fsp,
- locktype, lock_timeout,
- num_locks, locks,
- &async);
- TALLOC_FREE(locks);
- if (!NT_STATUS_IS_OK(status)) {
- END_PROFILE(SMBlockingX);
- reply_nterror(req, status);
- return;
- }
- if (async) {
+ subreq = smbd_smb1_do_locks_send(
+ fsp,
+ req->sconn->ev_ctx,
+ &req,
+ fsp,
+ lock_timeout,
+ large_file_format,
+ WINDOWS_LOCK,
+ num_locks,
+ locks);
+ if (subreq == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
END_PROFILE(SMBlockingX);
return;
}
+ tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
+ END_PROFILE(SMBlockingX);
+}
-done:
- reply_outbuf(req, 2, 0);
- SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
- SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
+static void reply_lockingx_done(struct tevent_req *subreq)
+{
+ struct smb_request *req = NULL;
+ NTSTATUS status;
+ bool ok;
+
+ START_PROFILE(SMBlockingX);
+
+ ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
+ SMB_ASSERT(ok);
+
+ status = smbd_smb1_do_locks_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
- DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
- fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
+ if (NT_STATUS_IS_OK(status)) {
+ reply_outbuf(req, 2, 0);
+ SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+ SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
+ } else {
+ reply_nterror(req, status);
+ }
+ ok = srv_send_smb(req->xconn,
+ (char *)req->outbuf,
+ true,
+ req->seqnum+1,
+ IS_CONN_ENCRYPTED(req->conn),
+ NULL);
+ if (!ok) {
+ exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
+ }
+ TALLOC_FREE(req);
END_PROFILE(SMBlockingX);
}
NTSTATUS status;
START_PROFILE(SMBsetattrE);
- ZERO_STRUCT(ft);
+ init_smb_file_time(&ft);
if (req->wct < 7) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
* Convert the DOS times into unix times.
*/
- ft.atime = convert_time_t_to_timespec(
+ ft.atime = time_t_to_full_timespec(
srv_make_unix_date2(req->vwv+3));
- ft.mtime = convert_time_t_to_timespec(
+ ft.mtime = time_t_to_full_timespec(
srv_make_unix_date2(req->vwv+5));
- ft.create_time = convert_time_t_to_timespec(
+ ft.create_time = time_t_to_full_timespec(
srv_make_unix_date2(req->vwv+1));
reply_outbuf(req, 0, 0);
int mode;
files_struct *fsp;
struct timespec create_ts;
+ NTSTATUS status;
START_PROFILE(SMBgetattrE);
}
/* Do an fstat on this file */
- if(fsp_stat(fsp)) {
- reply_nterror(req, map_nt_error_from_unix(errno));
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
END_PROFILE(SMBgetattrE);
return;
}