summaryrefslogtreecommitdiff
path: root/source3/smbd/close.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2011-01-25 14:23:19 -0800
committerJeremy Allison <jra@samba.org>2011-01-25 14:23:19 -0800
commit44732734cca2328a8aceb2db9b577c923920f644 (patch)
tree05bc735662ba82137e96479322c4d3737bff9693 /source3/smbd/close.c
parenta65bce4e38d0b940286c7c93c226651e5fb45082 (diff)
downloadsamba-44732734cca2328a8aceb2db9b577c923920f644.tar.gz
samba-44732734cca2328a8aceb2db9b577c923920f644.tar.bz2
samba-44732734cca2328a8aceb2db9b577c923920f644.zip
Fix bug #7863 - Unlink may unlink wrong file when hardlinks are involved.
Do this by keeping a linked list of delete on close tokens, one for each filename that identifies a path to the dev/inode. Use the jenkins hash of the pathname to identify the correct token.
Diffstat (limited to 'source3/smbd/close.c')
-rw-r--r--source3/smbd/close.c59
1 files changed, 34 insertions, 25 deletions
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index a6610e58f1..25ed9a3c4d 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -275,6 +275,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
NTSTATUS status = NT_STATUS_OK;
NTSTATUS tmp_status;
struct file_id id;
+ const UNIX_USER_TOKEN *del_token = NULL;
/* Ensure any pending write time updates are done. */
if (fsp->update_write_time_event) {
@@ -328,7 +329,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
fsp_str_dbg(fsp)));
}
- if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
+ if (fsp->initial_delete_on_close &&
+ !is_delete_on_close_set(lck, fsp->name_hash)) {
bool became_user = False;
/* Initial delete on close was set and no one else
@@ -339,21 +341,23 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
became_user = True;
}
fsp->delete_on_close = true;
- set_delete_on_close_lck(lck, True, get_current_utok(conn));
+ set_delete_on_close_lck(fsp, lck, True, get_current_utok(conn));
if (became_user) {
unbecome_user();
}
}
- delete_file = lck->delete_on_close;
+ delete_file = is_delete_on_close_set(lck, fsp->name_hash);
if (delete_file) {
int i;
- /* See if others still have the file open. If this is the
- * case, then don't delete. If all opens are POSIX delete now. */
+ /* See if others still have the file open via this pathname.
+ If this is the case, then don't delete. If all opens are
+ POSIX delete now. */
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *e = &lck->share_modes[i];
- if (is_valid_share_mode_entry(e)) {
+ if (is_valid_share_mode_entry(e) &&
+ e->name_hash == fsp->name_hash) {
if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
continue;
}
@@ -372,9 +376,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
* reference to a file.
*/
- if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
- || !delete_file
- || (lck->delete_token == NULL)) {
+ if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) ||
+ !delete_file) {
TALLOC_FREE(lck);
return NT_STATUS_OK;
}
@@ -391,23 +394,26 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
*/
fsp->update_write_time_on_close = false;
- if (!unix_token_equal(lck->delete_token, get_current_utok(conn))) {
+ del_token = get_delete_on_close_token(lck, fsp->name_hash);
+ SMB_ASSERT(del_token != NULL);
+
+ if (!unix_token_equal(del_token, get_current_utok(conn))) {
/* Become the user who requested the delete. */
DEBUG(5,("close_remove_share_mode: file %s. "
"Change user to uid %u\n",
fsp_str_dbg(fsp),
- (unsigned int)lck->delete_token->uid));
+ (unsigned int)del_token->uid));
if (!push_sec_ctx()) {
smb_panic("close_remove_share_mode: file %s. failed to push "
"sec_ctx.\n");
}
- set_sec_ctx(lck->delete_token->uid,
- lck->delete_token->gid,
- lck->delete_token->ngroups,
- lck->delete_token->groups,
+ set_sec_ctx(del_token->uid,
+ del_token->gid,
+ del_token->ngroups,
+ del_token->groups,
NULL);
changed_user = true;
@@ -481,7 +487,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
*/
fsp->delete_on_close = false;
- set_delete_on_close_lck(lck, False, NULL);
+ set_delete_on_close_lck(fsp, lck, false, NULL);
done:
@@ -944,6 +950,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
bool delete_dir = False;
NTSTATUS status = NT_STATUS_OK;
NTSTATUS status1 = NT_STATUS_OK;
+ const UNIX_USER_TOKEN *del_token = NULL;
/*
* NT can set delete_on_close of the last open
@@ -978,14 +985,16 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
}
send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
fsp->fsp_name->base_name);
- set_delete_on_close_lck(lck, True, get_current_utok(fsp->conn));
+ set_delete_on_close_lck(fsp, lck, true,
+ get_current_utok(fsp->conn));
fsp->delete_on_close = true;
if (became_user) {
unbecome_user();
}
}
- delete_dir = lck->delete_on_close;
+ del_token = get_delete_on_close_token(lck, fsp->name_hash);
+ delete_dir = (del_token != NULL);
if (delete_dir) {
int i;
@@ -993,7 +1002,8 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
* case, then don't delete. If all opens are POSIX delete now. */
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *e = &lck->share_modes[i];
- if (is_valid_share_mode_entry(e)) {
+ if (is_valid_share_mode_entry(e) &&
+ e->name_hash == fsp->name_hash) {
if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
continue;
}
@@ -1004,8 +1014,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
}
if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
- delete_dir &&
- lck->delete_token) {
+ delete_dir) {
/* Become the user who requested the delete. */
@@ -1013,10 +1022,10 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
smb_panic("close_directory: failed to push sec_ctx.\n");
}
- set_sec_ctx(lck->delete_token->uid,
- lck->delete_token->gid,
- lck->delete_token->ngroups,
- lck->delete_token->groups,
+ set_sec_ctx(del_token->uid,
+ del_token->gid,
+ del_token->ngroups,
+ del_token->groups,
NULL);
TALLOC_FREE(lck);