empty access mask is only denied on SMB2
[kai/samba.git] / source4 / ntvfs / posix / pvfs_acl.c
index 4302b7f890fbd24852f6763a6df4d72f8b9650ce..d479f1e2ee0e452ec48243d3a6db4ec7d9e14a68 100644 (file)
@@ -24,6 +24,7 @@
 #include "vfs_posix.h"
 #include "librpc/gen_ndr/xattr.h"
 #include "libcli/security/security.h"
+#include "param/param.h"
 
 
 /* the list of currently registered ACL backends */
@@ -38,7 +39,7 @@ static int num_backends;
   The 'name' can be later used by other backends to find the operations
   structure for this backend.  
 */
-_PUBLIC_ NTSTATUS pvfs_acl_register(const struct pvfs_acl_ops *ops)
+NTSTATUS pvfs_acl_register(const struct pvfs_acl_ops *ops)
 {
        struct pvfs_acl_ops *new_ops;
 
@@ -66,7 +67,7 @@ _PUBLIC_ NTSTATUS pvfs_acl_register(const struct pvfs_acl_ops *ops)
 /*
   return the operations structure for a named backend
 */
-_PUBLIC_ const struct pvfs_acl_ops *pvfs_acl_backend_byname(const char *name)
+const struct pvfs_acl_ops *pvfs_acl_backend_byname(const char *name)
 {
        int i;
 
@@ -79,6 +80,27 @@ _PUBLIC_ const struct pvfs_acl_ops *pvfs_acl_backend_byname(const char *name)
        return NULL;
 }
 
+NTSTATUS pvfs_acl_init(struct loadparm_context *lp_ctx)
+{
+       static bool initialized = false;
+       extern NTSTATUS pvfs_acl_nfs4_init(void);
+       extern NTSTATUS pvfs_acl_xattr_init(void);
+       init_module_fn static_init[] = { STATIC_pvfs_acl_MODULES };
+       init_module_fn *shared_init;
+
+       if (initialized) return NT_STATUS_OK;
+       initialized = true;
+
+       shared_init = load_samba_modules(NULL, lp_ctx, "pvfs_acl");
+
+       run_init_functions(static_init);
+       run_init_functions(shared_init);
+
+       talloc_free(shared_init);
+
+       return NT_STATUS_OK;
+}
+
 
 /*
   map a single access_mask from generic to specific bits for files/dirs
@@ -126,6 +148,8 @@ static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
        NTSTATUS status;
        struct security_ace ace;
        mode_t mode;
+       struct id_mapping *ids;
+       struct composite_context *ctx;
 
        *psd = security_descriptor_initialise(req);
        if (*psd == NULL) {
@@ -133,15 +157,33 @@ static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
        }
        sd = *psd;
 
-       status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       ids = talloc_zero_array(sd, struct id_mapping, 2);
+       NT_STATUS_HAVE_NO_MEMORY(ids);
+
+       ids[0].unixid = talloc(ids, struct unixid);
+       NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid);
+
+       ids[0].unixid->id = name->st.st_uid;
+       ids[0].unixid->type = ID_TYPE_UID;
+       ids[0].sid = NULL;
+
+       ids[1].unixid = talloc(ids, struct unixid);
+       NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid);
+
+       ids[1].unixid->id = name->st.st_gid;
+       ids[1].unixid->type = ID_TYPE_GID;
+       ids[1].sid = NULL;
+
+       ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
 
+       status = wbc_xids_to_sids_recv(ctx, &ids);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       sd->owner_sid = talloc_steal(sd, ids[0].sid);
+       sd->group_sid = talloc_steal(sd, ids[1].sid);
+
+       talloc_free(ids);
        sd->type |= SEC_DESC_DACL_PRESENT;
 
        mode = name->st.st_mode;
@@ -248,6 +290,8 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
        gid_t old_gid = -1;
        uid_t new_uid = -1;
        gid_t new_gid = -1;
+       struct id_mapping *ids;
+       struct composite_context *ctx;
 
        if (pvfs->acl_ops != NULL) {
                status = pvfs->acl_ops->acl_load(pvfs, name, fd, req, &sd);
@@ -259,6 +303,12 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
                return status;
        }
 
+       ids = talloc(req, struct id_mapping);
+       NT_STATUS_HAVE_NO_MEMORY(ids);
+       ids->unixid = NULL;
+       ids->sid = NULL;
+       ids->status = NT_STATUS_NONE_MAPPED;
+
        new_sd = info->set_secdesc.in.sd;
        orig_sd = *sd;
 
@@ -271,8 +321,16 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
                        return NT_STATUS_ACCESS_DENIED;
                }
                if (!dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) {
-                       status = sidmap_sid_to_unixuid(pvfs->sidmap, new_sd->owner_sid, &new_uid);
+                       ids->sid = new_sd->owner_sid;
+                       ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx, ids, 1, ids);
+                       NT_STATUS_HAVE_NO_MEMORY(ctx);
+                       status = wbc_sids_to_xids_recv(ctx, &ids);
                        NT_STATUS_NOT_OK_RETURN(status);
+
+                       if (ids->unixid->type == ID_TYPE_BOTH ||
+                           ids->unixid->type == ID_TYPE_UID) {
+                               new_uid = ids->unixid->id;
+                       }
                }
                sd->owner_sid = new_sd->owner_sid;
        }
@@ -281,8 +339,17 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
                        return NT_STATUS_ACCESS_DENIED;
                }
                if (!dom_sid_equal(sd->group_sid, new_sd->group_sid)) {
-                       status = sidmap_sid_to_unixgid(pvfs->sidmap, new_sd->group_sid, &new_gid);
+                       ids->sid = new_sd->group_sid;
+                       ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx, ids, 1, ids);
+                       NT_STATUS_HAVE_NO_MEMORY(ctx);
+                       status = wbc_sids_to_xids_recv(ctx, &ids);
                        NT_STATUS_NOT_OK_RETURN(status);
+
+                       if (ids->unixid->type == ID_TYPE_BOTH ||
+                           ids->unixid->type == ID_TYPE_GID) {
+                               new_gid = ids->unixid->id;
+                       }
+
                }
                sd->group_sid = new_sd->group_sid;
        }
@@ -365,7 +432,7 @@ NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
 /*
   check the read only bit against any of the write access bits
 */
-static BOOL pvfs_read_only(struct pvfs_state *pvfs, uint32_t access_mask)
+static bool pvfs_read_only(struct pvfs_state *pvfs, uint32_t access_mask)
 {
        if ((pvfs->flags & PVFS_FLAG_READONLY) &&
            (access_mask & (SEC_FILE_WRITE_DATA |
@@ -376,9 +443,9 @@ static BOOL pvfs_read_only(struct pvfs_state *pvfs, uint32_t access_mask)
                            SEC_STD_WRITE_DAC | 
                            SEC_STD_WRITE_OWNER | 
                            SEC_DIR_DELETE_CHILD))) {
-               return True;
+               return true;
        }
-       return False;
+       return false;
 }
 
 /*
@@ -412,14 +479,18 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
        }
 
        if (uid != 0 && (*access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
-               return NT_STATUS_PRIVILEGE_NOT_HELD;
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        if (*access_mask & ~max_bits) {
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       *access_mask |= SEC_FILE_READ_ATTRIBUTE;
+       if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) {
+               /* on SMB, this bit is always granted, even if not
+                  asked for */
+               *access_mask |= SEC_FILE_READ_ATTRIBUTE;
+       }
 
        return NT_STATUS_OK;
 }
@@ -440,6 +511,12 @@ NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
        NTSTATUS status;
        struct security_descriptor *sd;
 
+       /* on SMB2 a blank access mask is always denied */
+       if (pvfs->ntvfs->ctx->protocol == PROTOCOL_SMB2 &&
+           *access_mask == 0) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (pvfs_read_only(pvfs, *access_mask)) {
                return NT_STATUS_ACCESS_DENIED;
        }
@@ -451,7 +528,9 @@ NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
 
        /* expand the generic access bits to file specific bits */
        *access_mask = pvfs_translate_mask(*access_mask);
-       *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
+       if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) {
+               *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
+       }
 
        status = pvfs_acl_load(pvfs, name, -1, acl);
        if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
@@ -473,8 +552,11 @@ NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
        /* check the acl against the required access mask */
        status = sec_access_check(sd, token, *access_mask, access_mask);
 
-       /* this bit is always granted, even if not asked for */
-       *access_mask |= SEC_FILE_READ_ATTRIBUTE;
+       if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) {
+               /* on SMB, this bit is always granted, even if not
+                  asked for */
+               *access_mask |= SEC_FILE_READ_ATTRIBUTE;
+       }
 
        talloc_free(acl);
        
@@ -548,24 +630,24 @@ NTSTATUS pvfs_access_check_parent(struct pvfs_state *pvfs,
 /*
   determine if an ACE is inheritable
 */
-static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
+static bool pvfs_inheritable_ace(struct pvfs_state *pvfs,
                                 const struct security_ace *ace,
-                                BOOL container)
+                                bool container)
 {
        if (!container) {
                return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
        }
 
        if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
-               return True;
+               return true;
        }
 
        if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
            !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
 /*
@@ -576,7 +658,7 @@ static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs, 
                                      struct security_descriptor *parent_sd,
                                      struct security_descriptor *sd,
-                                     BOOL container)
+                                     bool container)
 {
        int i;
        
@@ -663,7 +745,9 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
        NTSTATUS status;
        struct pvfs_filename *parent;
        struct security_descriptor *parent_sd, *sd;
-       BOOL container;
+       bool container;
+       struct id_mapping *ids;
+       struct composite_context *ctx;
 
        /* form the parents path */
        status = pvfs_resolve_parent(pvfs, req, name, &parent);
@@ -705,18 +789,35 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       ids = talloc_array(sd, struct id_mapping, 2);
+       NT_STATUS_HAVE_NO_MEMORY(ids);
+
+       ids[0].unixid = talloc(ids, struct unixid);
+       NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid);
+       ids[0].unixid->id = name->st.st_uid;
+       ids[0].unixid->type = ID_TYPE_UID;
+       ids[0].sid = NULL;
+       ids[0].status = NT_STATUS_NONE_MAPPED;
+
+       ids[1].unixid = talloc(ids, struct unixid);
+       NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid);
+       ids[1].unixid->id = name->st.st_gid;
+       ids[1].unixid->type = ID_TYPE_GID;
+       ids[1].sid = NULL;
+       ids[1].status = NT_STATUS_NONE_MAPPED;
+
+       ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       status = wbc_xids_to_sids_recv(ctx, &ids);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       sd->owner_sid = talloc_steal(sd, ids[0].sid);
+       sd->group_sid = talloc_steal(sd, ids[1].sid);
 
        sd->type |= SEC_DESC_DACL_PRESENT;
 
-       container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
+       container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? true:false;
 
        /* fill in the aces from the parent */
        status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
@@ -736,3 +837,15 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
        
        return status;
 }
+
+/*
+  return the maximum allowed access mask
+*/
+NTSTATUS pvfs_access_maximal_allowed(struct pvfs_state *pvfs, 
+                                    struct ntvfs_request *req,
+                                    struct pvfs_filename *name,
+                                    uint32_t *maximal_access)
+{
+       *maximal_access = SEC_FLAG_MAXIMUM_ALLOWED;
+       return pvfs_access_check(pvfs, req, name, maximal_access);
+}