s3: Slightly simplify the logic in defer_open
[kai/samba.git] / source3 / smbd / open.c
index 8be5e852702db13e29bb93e604fb8dff06293af6..433bc090228f6b829401391f3b7c55c8a49aba9c 100644 (file)
@@ -27,6 +27,7 @@
 #include "fake_file.h"
 #include "../libcli/security/security.h"
 #include "../librpc/gen_ndr/ndr_security.h"
+#include "../librpc/gen_ndr/open_files.h"
 #include "auth.h"
 #include "messages.h"
 
@@ -910,8 +911,7 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
                          "share entry with an open file\n");
        }
 
-       if (is_deferred_open_entry(share_entry) ||
-           is_unused_share_mode_entry(share_entry)) {
+       if (is_deferred_open_entry(share_entry)) {
                goto panic;
        }
 
@@ -1275,11 +1275,9 @@ static void defer_open(struct share_mode_lock *lck,
        for (i=0; i<lck->num_share_modes; i++) {
                struct share_mode_entry *e = &lck->share_modes[i];
 
-               if (!is_deferred_open_entry(e)) {
-                       continue;
-               }
-
-               if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) {
+               if (is_deferred_open_entry(e) &&
+                   procid_is_me(&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));
@@ -1547,10 +1545,10 @@ void remove_deferred_open_entry(struct file_id id, uint64_t mid,
                        NULL, NULL, NULL);
        if (lck == NULL) {
                DEBUG(0, ("could not get share mode lock\n"));
-       } else {
-               del_deferred_open_entry(lck, mid, pid);
-               TALLOC_FREE(lck);
+               return;
        }
+       del_deferred_open_entry(lck, mid, pid);
+       TALLOC_FREE(lck);
 }
 
 /****************************************************************
@@ -2991,7 +2989,6 @@ void msg_file_was_renamed(struct messaging_context *msg,
                          struct server_id server_id,
                          DATA_BLOB *data)
 {
-       struct smbd_server_connection *sconn;
        files_struct *fsp;
        char *frm = (char *)data->data;
        struct file_id id;
@@ -3001,12 +2998,9 @@ void msg_file_was_renamed(struct messaging_context *msg,
        struct smb_filename *smb_fname = NULL;
        size_t sp_len, bn_len;
        NTSTATUS status;
-
-       sconn = msg_ctx_to_sconn(msg);
-       if (sconn == NULL) {
-               DEBUG(1, ("could not find sconn\n"));
-               return;
-       }
+       struct smbd_server_connection *sconn =
+               talloc_get_type_abort(private_data,
+               struct smbd_server_connection);
 
        if (data->data == NULL
            || data->length < MSG_FILE_RENAMED_MIN_SIZE + 2) {
@@ -3185,6 +3179,109 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
        return status;
 }
 
+/*********************************************************************
+ Create a default ACL by inheriting from the parent. If no inheritance
+ from the parent available, don't set anything. This will leave the actual
+ permissions the new file or directory already got from the filesystem
+ as the NT ACL when read.
+*********************************************************************/
+
+static NTSTATUS inherit_new_acl(files_struct *fsp)
+{
+       TALLOC_CTX *ctx = talloc_tos();
+       char *parent_name = NULL;
+       struct security_descriptor *parent_desc = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+       struct security_descriptor *psd = NULL;
+       struct dom_sid *owner_sid = NULL;
+       struct dom_sid *group_sid = NULL;
+       uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
+       bool inherit_owner = lp_inherit_owner(SNUM(fsp->conn));
+       bool inheritable_components = false;
+       size_t size = 0;
+
+       if (!parent_dirname(ctx, fsp->fsp_name->base_name, &parent_name, NULL)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = SMB_VFS_GET_NT_ACL(fsp->conn,
+                               parent_name,
+                               (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
+                               &parent_desc);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       inheritable_components = sd_has_inheritable_components(parent_desc,
+                                       fsp->is_directory);
+
+       if (!inheritable_components && !inherit_owner) {
+               /* Nothing to inherit and not setting owner. */
+               return NT_STATUS_OK;
+       }
+
+       /* Create an inherited descriptor from the parent. */
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
+                       fsp_str_dbg(fsp) ));
+               NDR_PRINT_DEBUG(security_descriptor, parent_desc);
+       }
+
+       /* Inherit from parent descriptor if "inherit owner" set. */
+       if (inherit_owner) {
+               owner_sid = parent_desc->owner_sid;
+               group_sid = parent_desc->group_sid;
+       }
+
+       if (owner_sid == NULL) {
+               owner_sid = &fsp->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+       }
+       if (group_sid == NULL) {
+               group_sid = &fsp->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
+       }
+
+       status = se_create_child_secdesc(ctx,
+                       &psd,
+                       &size,
+                       parent_desc,
+                       owner_sid,
+                       group_sid,
+                       fsp->is_directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* If inheritable_components == false,
+          se_create_child_secdesc()
+          creates a security desriptor with a NULL dacl
+          entry, but with SEC_DESC_DACL_PRESENT. We need
+          to remove that flag. */
+
+       if (!inheritable_components) {
+               security_info_sent &= ~SECINFO_DACL;
+               psd->type &= ~SEC_DESC_DACL_PRESENT;
+       }
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
+                       fsp_str_dbg(fsp) ));
+               NDR_PRINT_DEBUG(security_descriptor, psd);
+       }
+
+       if (inherit_owner) {
+               /* We need to be root to force this. */
+               become_root();
+       }
+       status = SMB_VFS_FSET_NT_ACL(fsp,
+                       security_info_sent,
+                       psd);
+       if (inherit_owner) {
+               unbecome_root();
+       }
+       return status;
+}
+
 /*
  * Wrapper around open_file_ntcreate and open_directory
  */
@@ -3457,42 +3554,51 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                }
        }
 
-       /*
-        * According to the MS documentation, the only time the security
-        * descriptor is applied to the opened file is iff we *created* the
-        * file; an existing file stays the same.
-        *
-        * Also, it seems (from observation) that you can open the file with
-        * any access mask but you can still write the sd. We need to override
-        * the granted access before we call set_sd
-        * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>.
-        */
-
-       if ((sd != NULL) && (info == FILE_WAS_CREATED)
-           && lp_nt_acl_support(SNUM(conn))) {
+       if ((info == FILE_WAS_CREATED) && lp_nt_acl_support(SNUM(conn)) &&
+                               fsp->base_fsp == NULL) {
+               if (sd != NULL) {
+                       /*
+                        * According to the MS documentation, the only time the security
+                        * descriptor is applied to the opened file is iff we *created* the
+                        * file; an existing file stays the same.
+                        *
+                        * Also, it seems (from observation) that you can open the file with
+                        * any access mask but you can still write the sd. We need to override
+                        * the granted access before we call set_sd
+                        * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>.
+                        */
 
-               uint32_t sec_info_sent;
-               uint32_t saved_access_mask = fsp->access_mask;
+                       uint32_t sec_info_sent;
+                       uint32_t saved_access_mask = fsp->access_mask;
 
-               sec_info_sent = get_sec_info(sd);
+                       sec_info_sent = get_sec_info(sd);
 
-               fsp->access_mask = FILE_GENERIC_ALL;
+                       fsp->access_mask = FILE_GENERIC_ALL;
 
-               /* Convert all the generic bits. */
-               security_acl_map_generic(sd->dacl, &file_generic_mapping);
-               security_acl_map_generic(sd->sacl, &file_generic_mapping);
+                       /* Convert all the generic bits. */
+                       security_acl_map_generic(sd->dacl, &file_generic_mapping);
+                       security_acl_map_generic(sd->sacl, &file_generic_mapping);
 
-               if (sec_info_sent & (SECINFO_OWNER|
-                                       SECINFO_GROUP|
-                                       SECINFO_DACL|
-                                       SECINFO_SACL)) {
-                       status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
-               }
+                       if (sec_info_sent & (SECINFO_OWNER|
+                                               SECINFO_GROUP|
+                                               SECINFO_DACL|
+                                               SECINFO_SACL)) {
+                               status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
+                       }
 
-               fsp->access_mask = saved_access_mask;
+                       fsp->access_mask = saved_access_mask;
 
-               if (!NT_STATUS_IS_OK(status)) {
-                       goto fail;
+                       if (!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+               } else if (lp_inherit_acls(SNUM(conn))) {
+                       /* Inherit from parent. Errors here are not fatal. */
+                       status = inherit_new_acl(fsp);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(10,("inherit_new_acl: failed for %s with %s\n",
+                                       fsp_str_dbg(fsp),
+                                       nt_errstr(status) ));
+                       }
                }
        }