#include "auth.h"
#include "serverid.h"
#include "messages.h"
+#include "source3/lib/dbwrap/dbwrap_watch.h"
extern const struct generic_mapping file_generic_mapping;
struct security_descriptor *sd = NULL;
uint32_t rejected_share_access;
uint32_t rejected_mask = access_mask;
+ uint32_t do_not_check_mask = 0;
rejected_share_access = access_mask & ~(conn->share_access);
* se_file_access_check() also takes care of
* owner WRITE_DAC and READ_CONTROL.
*/
+ do_not_check_mask = FILE_READ_ATTRIBUTES;
+
+ /*
+ * Samba 3.6 and earlier granted execute access even
+ * if the ACL did not contain execute rights.
+ * Samba 4.0 is more correct and checks it.
+ * The compatibilty mode allows to skip this check
+ * to smoothen upgrades.
+ */
+ if (lp_acl_allow_execute_always(SNUM(conn))) {
+ do_not_check_mask |= FILE_EXECUTE;
+ }
+
status = se_file_access_check(sd,
get_current_nttok(conn),
use_privs,
- (access_mask & ~FILE_READ_ATTRIBUTES),
+ (access_mask & ~do_not_check_mask),
&rejected_mask);
DEBUG(10,("smbd_check_access_rights: file %s requesting "
return;
}
- if (is_deferred_open_entry(share_entry) &&
- !open_was_deferred(sconn, share_entry->op_mid))
- {
- char *str = talloc_asprintf(talloc_tos(),
- "Got a deferred entry without a request: "
- "PANIC: %s\n",
- share_mode_str(talloc_tos(), num, share_entry));
- smb_panic(str);
- }
-
if (!is_valid_share_mode_entry(share_entry)) {
return;
}
"share entry with an open file\n");
}
- if (is_deferred_open_entry(share_entry)) {
- goto panic;
- }
-
if ((share_entry->op_type == NO_OPLOCK) &&
(fsp->oplock_type == FAKE_LEVEL_II_OPLOCK))
{
/* Create the message. */
share_mode_entry_to_message(msg, exclusive);
- /* Add in the FORCE_OPLOCK_BREAK_TO_NONE bit in the message if set. We
- don't want this set in the share mode struct pointed to by lck. */
-
- if (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE) {
- SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET,
- exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
- }
-
status = messaging_send_buf(fsp->conn->sconn->msg_ctx, exclusive->pid,
MSG_SMB_BREAK_REQUEST,
- (uint8 *)msg,
- MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ (uint8 *)msg, sizeof(msg));
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("Could not send oplock break message: %s\n",
nt_errstr(status)));
}
for (i=0; i<lck->data->num_share_modes; i++) {
- if (!is_valid_share_mode_entry(&lck->data->share_modes[i])) {
+ struct share_mode_entry *e = &lck->data->share_modes[i];
+
+ if (!is_valid_share_mode_entry(e)) {
continue;
}
- if (lck->data->share_modes[i].op_type == NO_OPLOCK &&
- is_stat_open(lck->data->share_modes[i].access_mask)) {
+ if (e->op_type == NO_OPLOCK && is_stat_open(e->access_mask)) {
/* We ignore stat opens in the table - they
always have NO_OPLOCK and never get or
cause breaks. JRA. */
continue;
}
- if (BATCH_OPLOCK_TYPE(lck->data->share_modes[i].op_type)) {
+ if (BATCH_OPLOCK_TYPE(e->op_type)) {
/* batch - can only be one. */
if (share_mode_stale_pid(lck->data, i)) {
DEBUG(10, ("Found stale batch oplock\n"));
if (*pp_ex_or_batch || *pp_batch || *got_level2 || *got_no_oplock) {
smb_panic("Bad batch oplock entry.");
}
- *pp_batch = &lck->data->share_modes[i];
+ *pp_batch = e;
}
- if (EXCLUSIVE_OPLOCK_TYPE(lck->data->share_modes[i].op_type)) {
+ if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) {
if (share_mode_stale_pid(lck->data, i)) {
DEBUG(10, ("Found stale duplicate oplock\n"));
continue;
if (*pp_ex_or_batch || *got_level2 || *got_no_oplock) {
smb_panic("Bad exclusive or batch oplock entry.");
}
- *pp_ex_or_batch = &lck->data->share_modes[i];
+ *pp_ex_or_batch = e;
}
- if (LEVEL_II_OPLOCK_TYPE(lck->data->share_modes[i].op_type)) {
+ if (LEVEL_II_OPLOCK_TYPE(e->op_type)) {
if (*pp_batch || *pp_ex_or_batch) {
if (share_mode_stale_pid(lck->data, i)) {
DEBUG(10, ("Found stale LevelII "
*got_level2 = true;
}
- if (lck->data->share_modes[i].op_type == NO_OPLOCK) {
+ if (e->op_type == NO_OPLOCK) {
if (*pp_batch || *pp_ex_or_batch) {
if (share_mode_stale_pid(lck->data, i)) {
DEBUG(10, ("Found stale NO_OPLOCK "
if (!br_lck)
return false;
- return br_lck->num_locks > 0 ? true : false;
+ return (brl_num_locks(br_lck) > 0);
}
static void grant_fsp_oplock_type(files_struct *fsp,
return (timeval_compare(&end_time, &now) < 0);
}
+struct defer_open_state {
+ struct smbd_server_connection *sconn;
+ uint64_t mid;
+};
+
+static void defer_open_done(struct tevent_req *req);
+
/****************************************************************************
Handle the 1 second delay in returning a SHARING_VIOLATION error.
****************************************************************************/
struct smb_request *req,
struct deferred_open_record *state)
{
- struct server_id self = messaging_server_id(req->sconn->msg_ctx);
-
- /* Paranoia check */
-
- if (lck) {
- int i;
-
- for (i=0; i<lck->data->num_share_modes; i++) {
- struct share_mode_entry *e = &lck->data->share_modes[i];
-
- if (is_deferred_open_entry(e) &&
- serverid_equal(&self, &e->pid) &&
- (e->op_mid == req->mid)) {
- DEBUG(0, ("Trying to defer an already deferred "
- "request: mid=%llu, exiting\n",
- (unsigned long long)req->mid));
- TALLOC_FREE(lck);
- exit_server("attempt to defer a deferred request");
- }
- }
- }
-
- /* End paranoia check */
-
DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
"open entry for mid %llu\n",
(unsigned int)request_time.tv_sec,
exit_server("push_deferred_open_message_smb failed");
}
if (lck) {
- add_deferred_open(lck, req->mid, request_time, self, state->id);
+ struct defer_open_state *watch_state;
+ struct tevent_req *watch_req;
+ bool ret;
+
+ watch_state = talloc(req->sconn, struct defer_open_state);
+ if (watch_state == NULL) {
+ exit_server("talloc failed");
+ }
+ watch_state->sconn = req->sconn;
+ watch_state->mid = req->mid;
+
+ DEBUG(10, ("defering mid %llu\n",
+ (unsigned long long)req->mid));
+
+ watch_req = dbwrap_record_watch_send(
+ watch_state, req->sconn->ev_ctx, lck->data->record,
+ req->sconn->msg_ctx);
+ if (watch_req == NULL) {
+ exit_server("Could not watch share mode record");
+ }
+ tevent_req_set_callback(watch_req, defer_open_done,
+ watch_state);
+
+ ret = tevent_req_set_endtime(
+ watch_req, req->sconn->ev_ctx,
+ timeval_sum(&request_time, &timeout));
+ SMB_ASSERT(ret);
}
}
+static void defer_open_done(struct tevent_req *req)
+{
+ struct defer_open_state *state = tevent_req_callback_data(
+ req, struct defer_open_state);
+ NTSTATUS status;
+ bool ret;
+
+ status = dbwrap_record_watch_recv(req, talloc_tos(), NULL);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
+ nt_errstr(status)));
+ /*
+ * Even if it failed, retry anyway. TODO: We need a way to
+ * tell a re-scheduled open about that error.
+ */
+ }
+
+ DEBUG(10, ("scheduling mid %llu\n", (unsigned long long)state->mid));
+
+ ret = schedule_deferred_open_message_smb(state->sconn, state->mid);
+ SMB_ASSERT(ret);
+ TALLOC_FREE(state);
+}
+
/****************************************************************************
On overwrite open ensure that the attributes match.
Remove the deferred open entry under lock.
****************************************************************************/
-void remove_deferred_open_entry(struct file_id id, uint64_t mid,
- struct server_id pid)
-{
- struct share_mode_lock *lck = get_existing_share_mode_lock(
- talloc_tos(), id);
- if (lck == NULL) {
- DEBUG(0, ("could not get share mode lock\n"));
- return;
- }
- del_deferred_open_entry(lck, mid, pid);
- TALLOC_FREE(lck);
-}
-
/****************************************************************************
Return true if this is a state pointer to an asynchronous create.
****************************************************************************/
* mean the same thing under DOS and Unix.
*/
- need_write =
- ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ||
- (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE));
-
+ need_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA));
if (!need_write) {
return O_RDONLY;
}
if (is_deferred_open_async(ptr)) {
SET_STAT_INVALID(smb_fname->st);
file_existed = false;
- } else {
- struct deferred_open_record *state = (struct deferred_open_record *)ptr;
- /* Remove the deferred open entry under lock. */
- remove_deferred_open_entry(
- state->id, req->mid,
- messaging_server_id(req->sconn->msg_ctx));
}
/* Ensure we don't reprocess this message. */
open_access_mask = access_mask;
- if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
+ if (flags2 & O_TRUNC) {
open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
}
if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_RETRY)) {
schedule_async_open(request_time, req);
}
- TALLOC_FREE(lck);
return fsp_open;
}
* just fail the open to prevent creating any problems
* in the open file db having the wrong dev/ino key.
*/
- TALLOC_FREE(lck);
fd_close(fsp);
DEBUG(1,("open_file_ntcreate: file %s - dev/ino mismatch. "
"Old (dev=0x%llu, ino =0x%llu). "
/*
* If we're returning a share violation, ensure we
- * cope with the braindead 1 second delay.
+ * cope with the braindead 1 second delay (SMB1 only).
*/
if (!(oplock_request & INTERNAL_OPEN_ONLY) &&
+ !conn->sconn->using_smb2 &&
lp_defer_sharing_violations()) {
struct timeval timeout;
struct deferred_open_record state;
(unsigned int)new_unx_mode));
}
- /* If this is a successful open, we must remove any deferred open
- * records. */
- if (req != NULL) {
- del_deferred_open_entry(lck, req->mid,
- messaging_server_id(req->sconn->msg_ctx));
- }
TALLOC_FREE(lck);
return NT_STATUS_OK;