#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 */
backends = talloc_realloc(talloc_autofree_context(), backends, struct pvfs_acl_backend, num_backends+1);
NT_STATUS_HAVE_NO_MEMORY(backends);
- new_ops = talloc_memdup(backends, ops, sizeof(*ops));
+ new_ops = (struct pvfs_acl_ops *)talloc_memdup(backends, ops, sizeof(*ops));
new_ops->name = talloc_strdup(new_ops, ops->name);
backends[num_backends].ops = new_ops;
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
return false;
}
+/*
+ see if we are a member of the appropriate unix group
+ */
+static bool pvfs_group_member(struct pvfs_state *pvfs, gid_t gid)
+{
+ int i, ngroups;
+ gid_t *groups;
+ if (getegid() == gid) {
+ return true;
+ }
+ ngroups = getgroups(0, NULL);
+ if (ngroups == 0) {
+ return false;
+ }
+ groups = talloc_array(pvfs, gid_t, ngroups);
+ if (groups == NULL) {
+ return false;
+ }
+ if (getgroups(ngroups, groups) != ngroups) {
+ talloc_free(groups);
+ return false;
+ }
+ for (i=0; i<ngroups; i++) {
+ if (groups[i] == gid) break;
+ }
+ talloc_free(groups);
+ return i < ngroups;
+}
+
/*
default access check function based on unix permissions
doing this saves on building a full security descriptor
{
uid_t uid = geteuid();
uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
+ struct security_token *token = req->session_info->security_token;
if (pvfs_read_only(pvfs, *access_mask)) {
return NT_STATUS_ACCESS_DENIED;
}
- /* owner and root get extra permissions */
- if (uid == 0) {
- max_bits |= SEC_STD_ALL | SEC_FLAG_SYSTEM_SECURITY;
- } else if (uid == name->st.st_uid) {
+ if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+ max_bits |= SEC_RIGHTS_PRIV_RESTORE;
+ }
+ if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
+ max_bits |= SEC_RIGHTS_PRIV_BACKUP;
+ }
+
+ if (uid == name->st.st_uid) {
max_bits |= SEC_STD_ALL;
}
- if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
- *access_mask = max_bits;
- return NT_STATUS_OK;
+ if ((name->st.st_mode & S_IWOTH) ||
+ ((name->st.st_mode & S_IWGRP) &&
+ pvfs_group_member(pvfs, name->st.st_gid))) {
+ max_bits |= SEC_STD_ALL;
}
- if (uid != 0 && (*access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
- return NT_STATUS_ACCESS_DENIED;
+ if (uwrap_enabled()) {
+ /* when running with the uid wrapper, files will be created
+ owned by the ruid, but we may have a different simulated
+ euid. We need to force the permission bits as though the
+ files owner matches the euid */
+ max_bits |= SEC_STD_ALL;
+ }
+
+ if (*access_mask & SEC_FLAG_MAXIMUM_ALLOWED) {
+ *access_mask |= max_bits;
+ *access_mask &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+ }
+
+ if ((*access_mask & SEC_FLAG_SYSTEM_SECURITY) &&
+ security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
+ max_bits |= SEC_FLAG_SYSTEM_SECURITY;
}
if (*access_mask & ~max_bits) {
+ DEBUG(0,(__location__ " denied access to '%s' - wanted 0x%08x but got 0x%08x (missing 0x%08x)\n",
+ name->full_name, *access_mask, max_bits, *access_mask & ~max_bits));
return NT_STATUS_ACCESS_DENIED;
}
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;
}