Second part of bugfix for bug #8837 - smbd crashes when deleting directory and veto...
authorJeremy Allison <jra@samba.org>
Wed, 4 Apr 2012 21:54:02 +0000 (14:54 -0700)
committerJeremy Allison <jra@samba.org>
Wed, 4 Apr 2012 21:58:42 +0000 (14:58 -0700)
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
source3/locking/locking.c
source3/locking/proto.h
source3/smbd/close.c
source3/smbd/reply.c
source3/smbd/trans2.c

index cefb75a2a3f9d27b7e7c1f4208b4691507c174b3..98e1c32db088667daf3c1b2568a1e76333c50eb1 100644 (file)
@@ -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;
 
index 149a79d27a440f542e6c7c81485c6f3024266a15..cc921527272b9708c2801cfa370a9e0712d7ea4e 100644 (file)
@@ -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)
index 3a6df37e93c4fe0594ac41d781d3c63f59cc1791..54badd91498c3b188811e7a207f69cbb7305dd65 100644 (file)
@@ -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);
index 34ce7858be4b858467221c84b4c89952088f103d..8b91da81d543c2563098dac83e4377fb0053aece 100644 (file)
@@ -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);
 
index 6e4bcab7741e467770a8a911d994283db4af1c29..884731088a92eeea77c47c7746ce7eedfd6e5b2a 100644 (file)
@@ -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;
index 24642cd8181760d67e98cdc43f7387b87078bb43..da552f5a51a7fcc0bbed91926ec2b5e050bd1747 100644 (file)
@@ -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;
        }