From c10ed730d481e3d5b6710999b11b8e6969e1c16e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 4 Apr 2012 14:54:02 -0700 Subject: Second part of bugfix for bug #8837 - smbd crashes when deleting directory and veto files are enabled. Store the 'struct security_token' as well as the 'struct security_unix_token' inside the locking db when setting a delete on close. --- source3/librpc/idl/open_files.idl | 1 + source3/locking/locking.c | 51 +++++++++++++++++++++++++++++++++------ source3/locking/proto.h | 10 ++++++-- source3/smbd/close.c | 23 ++++++++++++------ source3/smbd/reply.c | 8 ++++-- source3/smbd/trans2.c | 1 + 6 files changed, 74 insertions(+), 20 deletions(-) (limited to 'source3') diff --git a/source3/librpc/idl/open_files.idl b/source3/librpc/idl/open_files.idl index cefb75a2a3..98e1c32db0 100644 --- a/source3/librpc/idl/open_files.idl +++ b/source3/librpc/idl/open_files.idl @@ -27,6 +27,7 @@ interface open_files typedef [public] struct { uint32 name_hash; + security_token *delete_nt_token; security_unix_token *delete_token; } delete_token; diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 149a79d27a..cc92152727 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -867,6 +867,7 @@ static struct security_unix_token *copy_unix_token(TALLOC_CTX *ctx, const struct static bool add_delete_on_close_token(struct share_mode_data *d, uint32_t name_hash, + const struct security_token *nt_tok, const struct security_unix_token *tok) { struct delete_token *tmp, *dtl; @@ -880,6 +881,10 @@ static bool add_delete_on_close_token(struct share_mode_data *d, dtl = &d->delete_tokens[d->num_delete_tokens]; dtl->name_hash = name_hash; + dtl->delete_nt_token = dup_nt_token(d->delete_tokens, nt_tok); + if (dtl->delete_nt_token == NULL) { + return false; + } dtl->delete_token = copy_unix_token(d->delete_tokens, tok); if (dtl->delete_token == NULL) { return false; @@ -903,6 +908,7 @@ static bool add_delete_on_close_token(struct share_mode_data *d, void set_delete_on_close_lck(files_struct *fsp, struct share_mode_lock *lck, bool delete_on_close, + const struct security_token *nt_tok, const struct security_unix_token *tok) { struct share_mode_data *d = lck->data; @@ -910,8 +916,10 @@ void set_delete_on_close_lck(files_struct *fsp, bool ret; if (delete_on_close) { + SMB_ASSERT(nt_tok != NULL); SMB_ASSERT(tok != NULL); } else { + SMB_ASSERT(nt_tok == NULL); SMB_ASSERT(tok == NULL); } @@ -921,6 +929,7 @@ void set_delete_on_close_lck(files_struct *fsp, d->modified = true; if (delete_on_close == false) { /* Delete this entry. */ + TALLOC_FREE(dt->delete_nt_token); TALLOC_FREE(dt->delete_token); *dt = d->delete_tokens[ d->num_delete_tokens-1]; @@ -929,6 +938,9 @@ void set_delete_on_close_lck(files_struct *fsp, } /* Replace this token with the given tok. */ + TALLOC_FREE(dt->delete_nt_token); + dt->delete_nt_token = dup_nt_token(dt, nt_tok); + SMB_ASSERT(dt->delete_nt_token != NULL); TALLOC_FREE(dt->delete_token); dt->delete_token = copy_unix_token(dt, tok); SMB_ASSERT(dt->delete_token != NULL); @@ -940,11 +952,13 @@ void set_delete_on_close_lck(files_struct *fsp, return; } - ret = add_delete_on_close_token(lck->data, fsp->name_hash, tok); + ret = add_delete_on_close_token(lck->data, fsp->name_hash, nt_tok, tok); SMB_ASSERT(ret); } -bool set_delete_on_close(files_struct *fsp, bool delete_on_close, const struct security_unix_token *tok) +bool set_delete_on_close(files_struct *fsp, bool delete_on_close, + const struct security_token *nt_tok, + const struct security_unix_token *tok) { struct share_mode_lock *lck; @@ -958,8 +972,15 @@ bool set_delete_on_close(files_struct *fsp, bool delete_on_close, const struct s return False; } - set_delete_on_close_lck(fsp, lck, delete_on_close, - delete_on_close ? tok : NULL); + if (delete_on_close) { + set_delete_on_close_lck(fsp, lck, true, + nt_tok, + tok); + } else { + set_delete_on_close_lck(fsp, lck, false, + NULL, + NULL); + } if (fsp->is_directory) { SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name)); @@ -974,7 +995,15 @@ bool set_delete_on_close(files_struct *fsp, bool delete_on_close, const struct s return True; } -const struct security_unix_token *get_delete_on_close_token(struct share_mode_lock *lck, uint32_t name_hash) +/**************************************************************************** + Return the NT token and UNIX token if there's a match. Return true if + found, false if not. +****************************************************************************/ + +bool get_delete_on_close_token(struct share_mode_lock *lck, + uint32_t name_hash, + const struct security_token **pp_nt_tok, + const struct security_unix_token **pp_tok) { int i; @@ -986,15 +1015,21 @@ const struct security_unix_token *get_delete_on_close_token(struct share_mode_lo DEBUG(10,("get_delete_on_close_token: dtl->name_hash = 0x%x\n", (unsigned int)dt->name_hash )); if (dt->name_hash == name_hash) { - return dt->delete_token; + if (pp_nt_tok) { + *pp_nt_tok = dt->delete_nt_token; + } + if (pp_tok) { + *pp_tok = dt->delete_token; + } + return true; } } - return NULL; + return false; } bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash) { - return (get_delete_on_close_token(lck, name_hash) != NULL); + return get_delete_on_close_token(lck, name_hash, NULL, NULL); } bool set_sticky_write_time(struct file_id fileid, struct timespec write_time) diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 3a6df37e93..54badd9149 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -178,12 +178,18 @@ void del_deferred_open_entry(struct share_mode_lock *lck, uint64_t mid, struct server_id pid); bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp); bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp); -const struct security_unix_token *get_delete_on_close_token(struct share_mode_lock *lck, uint32_t name_hash); +bool get_delete_on_close_token(struct share_mode_lock *lck, + uint32_t name_hash, + const struct security_token **pp_nt_tok, + const struct security_unix_token **pp_tok); void set_delete_on_close_lck(files_struct *fsp, struct share_mode_lock *lck, bool delete_on_close, + const struct security_token *nt_tok, + const struct security_unix_token *tok); +bool set_delete_on_close(files_struct *fsp, bool delete_on_close, + const struct security_token *nt_tok, const struct security_unix_token *tok); -bool set_delete_on_close(files_struct *fsp, bool delete_on_close, const struct security_unix_token *tok); bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash); bool set_sticky_write_time(struct file_id fileid, struct timespec write_time); bool set_write_time(struct file_id fileid, struct timespec write_time); diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 34ce7858be..8b91da81d5 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -332,6 +332,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, NTSTATUS tmp_status; struct file_id id; const struct security_unix_token *del_token = NULL; + const struct security_token *del_nt_token = NULL; + bool got_tokens = false; /* Ensure any pending write time updates are done. */ if (fsp->update_write_time_event) { @@ -395,7 +397,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, became_user = True; } fsp->delete_on_close = true; - set_delete_on_close_lck(fsp, lck, True, get_current_utok(conn)); + set_delete_on_close_lck(fsp, lck, True, + get_current_nttok(conn), + get_current_utok(conn)); if (became_user) { unbecome_user(); } @@ -448,8 +452,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, */ fsp->update_write_time_on_close = false; - del_token = get_delete_on_close_token(lck, fsp->name_hash); - SMB_ASSERT(del_token != NULL); + got_tokens = get_delete_on_close_token(lck, fsp->name_hash, + &del_nt_token, &del_token); + SMB_ASSERT(got_tokens); if (!unix_token_equal(del_token, get_current_utok(conn))) { /* Become the user who requested the delete. */ @@ -468,7 +473,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, del_token->gid, del_token->ngroups, del_token->groups, - NULL); + del_nt_token); changed_user = true; } @@ -541,7 +546,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, */ fsp->delete_on_close = false; - set_delete_on_close_lck(fsp, lck, false, NULL); + set_delete_on_close_lck(fsp, lck, false, NULL, NULL); done: @@ -1010,6 +1015,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 struct security_token *del_nt_token = NULL; const struct security_unix_token *del_token = NULL; /* @@ -1044,6 +1050,7 @@ 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(fsp, lck, true, + get_current_nttok(fsp->conn), get_current_utok(fsp->conn)); fsp->delete_on_close = true; if (became_user) { @@ -1051,8 +1058,8 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, } } - del_token = get_delete_on_close_token(lck, fsp->name_hash); - delete_dir = (del_token != NULL); + delete_dir = get_delete_on_close_token(lck, fsp->name_hash, + &del_nt_token, &del_token); if (delete_dir) { int i; @@ -1084,7 +1091,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, del_token->gid, del_token->ngroups, del_token->groups, - NULL); + del_nt_token); TALLOC_FREE(lck); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 6e4bcab774..884731088a 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -2546,7 +2546,9 @@ static NTSTATUS do_unlink(connection_struct *conn, } /* The set is across all open files on this dev/inode pair. */ - if (!set_delete_on_close(fsp, True, conn->session_info->unix_token)) { + if (!set_delete_on_close(fsp, True, + conn->session_info->security_token, + conn->session_info->unix_token)) { close_file(req, fsp, NORMAL_CLOSE); return NT_STATUS_ACCESS_DENIED; } @@ -5664,7 +5666,9 @@ void reply_rmdir(struct smb_request *req) goto out; } - if (!set_delete_on_close(fsp, true, conn->session_info->unix_token)) { + if (!set_delete_on_close(fsp, true, + conn->session_info->security_token, + conn->session_info->unix_token)) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_ACCESS_DENIED); goto out; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 24642cd818..da552f5a51 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5885,6 +5885,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, /* The set is across all open files on this dev/inode pair. */ if (!set_delete_on_close(fsp, delete_on_close, + conn->session_info->security_token, conn->session_info->unix_token)) { return NT_STATUS_ACCESS_DENIED; } -- cgit