Final back port of fix for bug #8837 - smbd crashes when deleting directory and veto...
authorJeremy Allison <jra@samba.org>
Mon, 9 Apr 2012 21:15:22 +0000 (14:15 -0700)
committerKarolin Seeger <kseeger@samba.org>
Mon, 7 May 2012 13:09:10 +0000 (15:09 +0200)
Use ndr encoding to add the NT security token into the stored data when
delete on close is set.

librpc/idl/security.idl
source3/include/smb.h
source3/locking/locking.c
source3/locking/proto.h
source3/smbd/close.c
source3/smbd/reply.c
source3/smbd/trans2.c

index b58e099418fe65364d1789c8f7be463468e7032a..696d5a56fb76d9cbfd3e198c8d3ce87c4f99dbfd 100644 (file)
@@ -570,7 +570,7 @@ interface security
        } sec_desc_buf;
 
        /* This is not yet sent over the network, but is simply defined in IDL */
-       typedef [public] struct {
+       typedef [public,gensize] struct {
                uint32 num_sids;
                [size_is(num_sids)] dom_sid sids[*];
                se_privilege privilege_mask;
index 549ebb2bbaf025709b870ce205390bbe5da67355..873657a892fee37adee3457f4ff735ec04493ebb 100644 (file)
@@ -637,6 +637,7 @@ struct delete_token_list {
        struct delete_token_list *next, *prev;
        uint32_t name_hash;
        struct security_unix_token *delete_token;
+       struct security_token *delete_nt_token;
 };
 
 struct share_mode_lock {
index e04de795aaa76c08eaa4ab118ebefbc085734820..11d1a85ab7291d4b8ab4789ab1e8599f1d192370 100644 (file)
@@ -587,7 +587,7 @@ static int parse_delete_tokens_list(struct share_mode_lock *lck,
                                (ndr_pull_flags_fn_t)ndr_pull_security_unix_token);
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        DEBUG(1, ("parse_delete_tokens_list: "
-                               "ndr_pull_share_mode_data failed\n"));
+                               "ndr_pull_security_unix_token failed\n"));
                        return -1;
                }
 
@@ -596,6 +596,35 @@ static int parse_delete_tokens_list(struct share_mode_lock *lck,
                p += token_len;
                delete_tokens_size += token_len;
 
+               if (p >= end_ptr) {
+                       DEBUG(0,("parse_delete_tokens_list: corrupt data"));
+                       return -1;
+               }
+
+               pdtl->delete_nt_token = TALLOC_ZERO_P(pdtl, struct security_token);
+               if (pdtl->delete_nt_token == NULL) {
+                       DEBUG(0,("parse_delete_tokens_list: talloc failed"));
+                       return -1;
+               }
+
+               blob.data = p;
+               blob.length = end_ptr - p;
+
+               ndr_err = ndr_pull_struct_blob(&blob,
+                               pdtl,
+                               pdtl->delete_nt_token,
+                               (ndr_pull_flags_fn_t)ndr_pull_security_token);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       DEBUG(1, ("parse_delete_tokens_list: "
+                               "ndr_pull_security_token failed\n"));
+                       return -1;
+               }
+
+               token_len = ndr_size_security_token(pdtl->delete_nt_token, 0);
+
+               p += token_len;
+               delete_tokens_size += token_len;
+
                /* Add to the list. */
                DLIST_ADD(lck->delete_tokens, pdtl);
        }
@@ -738,7 +767,8 @@ static TDB_DATA unparse_share_modes(const struct share_mode_lock *lck)
        for (pdtl = lck->delete_tokens; pdtl; pdtl = pdtl->next) {
                num_delete_token_entries++;
                delete_tokens_size += sizeof(uint32_t) +
-                               ndr_size_security_unix_token(pdtl->delete_token, 0);
+                               ndr_size_security_unix_token(pdtl->delete_token, 0) +
+                               ndr_size_security_token(pdtl->delete_nt_token, 0);
        }
 
        result.dsize = sizeof(*data) +
@@ -778,6 +808,7 @@ static TDB_DATA unparse_share_modes(const struct share_mode_lock *lck)
        /* Store any delete on close tokens. */
        for (pdtl = lck->delete_tokens; pdtl; pdtl = pdtl->next) {
                struct security_unix_token *pdt = pdtl->delete_token;
+               struct security_token *pdt_nt = pdtl->delete_nt_token;
                uint8_t *p = result.dptr + offset;
                DATA_BLOB blob;
                enum ndr_err_code ndr_err;
@@ -797,6 +828,22 @@ static TDB_DATA unparse_share_modes(const struct share_mode_lock *lck)
 
                /* We know we have space here as we counted above. */
                memcpy(p, blob.data, blob.length);
+               p += blob.length;
+               offset += blob.length;
+               TALLOC_FREE(blob.data);
+
+               ndr_err = ndr_push_struct_blob(&blob,
+                               talloc_tos(),
+                               pdt_nt,
+                               (ndr_push_flags_fn_t)ndr_push_security_token);
+
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       smb_panic("ndr_push_security_token failed");
+               }
+
+               /* We know we have space here as we counted above. */
+               memcpy(p, blob.data, blob.length);
+               p += blob.length;
                offset += blob.length;
                TALLOC_FREE(blob.data);
        }
@@ -1470,6 +1517,7 @@ static struct security_unix_token *copy_unix_token(TALLOC_CTX *ctx, const struct
 
 static bool add_delete_on_close_token(struct share_mode_lock *lck,
                        uint32_t name_hash,
+                       const struct security_token *nt_tok,
                        const struct security_unix_token *tok)
 {
        struct delete_token_list *dtl;
@@ -1485,6 +1533,11 @@ static bool add_delete_on_close_token(struct share_mode_lock *lck,
                TALLOC_FREE(dtl);
                return false;
        }
+       dtl->delete_nt_token = dup_nt_token(dtl, nt_tok);
+       if (dtl->delete_nt_token == NULL) {
+               TALLOC_FREE(dtl);
+               return false;
+       }
        DLIST_ADD(lck->delete_tokens, dtl);
        lck->modified = true;
        return true;
@@ -1504,14 +1557,17 @@ static bool add_delete_on_close_token(struct share_mode_lock *lck,
 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 delete_token_list *dtl;
        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);
        }
 
@@ -1528,6 +1584,9 @@ void set_delete_on_close_lck(files_struct *fsp,
                                TALLOC_FREE(dtl->delete_token);
                                dtl->delete_token = copy_unix_token(dtl, tok);
                                SMB_ASSERT(dtl->delete_token != NULL);
+                               TALLOC_FREE(dtl->delete_nt_token);
+                               dtl->delete_nt_token = dup_nt_token(dtl, nt_tok);
+                               SMB_ASSERT(dtl->delete_nt_token != NULL);
                        }
                        return;
                }
@@ -1538,11 +1597,13 @@ void set_delete_on_close_lck(files_struct *fsp,
                return;
        }
 
-       ret = add_delete_on_close_token(lck, fsp->name_hash, tok);
+       ret = add_delete_on_close_token(lck, 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;
        
@@ -1557,8 +1618,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));
@@ -1573,7 +1641,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)
 {
        struct delete_token_list *dtl;
 
@@ -1584,15 +1660,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)dtl->name_hash ));
                if (dtl->name_hash == name_hash) {
-                       return dtl->delete_token;
+                       if (pp_nt_tok) {
+                               *pp_nt_tok = dtl->delete_nt_token;
+                       }
+                       if (pp_tok) {
+                               *pp_tok =  dtl->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 b7c8990b1afa1252c2c04ee3c36668db40431c02..7745da59ac31144845daf8ddfb9504f0b7066e0d 100644 (file)
@@ -173,12 +173,18 @@ void del_deferred_open_entry(struct share_mode_lock *lck, uint64_t mid,
 bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp);
 bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp);
 NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32 dosmode);
-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 a307f7020c63f8ddac59f8486532f4286efaed93..36cec1ae9cc8878aba3d6772097b42d5e29fa4be 100644 (file)
@@ -280,6 +280,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) {
@@ -345,7 +347,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();
                }
@@ -398,8 +402,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. */
@@ -418,7 +423,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;
        }
@@ -491,7 +496,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:
 
@@ -962,6 +967,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;
 
        /*
@@ -998,6 +1004,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) {
@@ -1005,8 +1012,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;
@@ -1038,7 +1045,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 c0e8a98e9af4989f2721fd4760382bd2e60e4707..ac471aa6ee94504299d234eb2a79e96acfa6a268 100644 (file)
@@ -2541,7 +2541,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->utok)) {
+       if (!set_delete_on_close(fsp, true,
+                               conn->session_info->security_token,
+                               &conn->session_info->utok)) {
                close_file(req, fsp, NORMAL_CLOSE);
                return NT_STATUS_ACCESS_DENIED;
        }
@@ -5650,7 +5652,9 @@ void reply_rmdir(struct smb_request *req)
                goto out;
        }
 
-       if (!set_delete_on_close(fsp, true, &conn->session_info->utok)) {
+       if (!set_delete_on_close(fsp, true,
+                       conn->session_info->security_token,
+                       &conn->session_info->utok)) {
                close_file(req, fsp, ERROR_CLOSE);
                reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                goto out;
index 6f933dda5e0012477ded5f2069ee3b06f777d574..c7cf1a27d7bcb1fd4306cbb0ba623306cd06ee6e 100644 (file)
@@ -5827,6 +5827,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->utok)) {
                return NT_STATUS_ACCESS_DENIED;
        }