#include "smbd/smbd.h"
#include "librpc/gen_ndr/ndr_xattr.h"
#include "include/smbprofile.h"
+#include "modules/non_posix_acls.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
};
-static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
+static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
uint32 share_mode, uint32 access_mask)
{
struct gpfs_config_data,
return -1);
+ if(!config->sharemodes) {
+ return 0;
+ }
+
START_PROFILE(syscall_kernel_flock);
kernel_flock(fsp->fh->fd, share_mode, access_mask);
- if (config->sharemodes
- && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
+ if (!set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
ret = -1;
}
}
}
+/*
+ * get the ACL from GPFS, allocated on the specified mem_ctx
+ * internally retries when initial buffer was too small
+ *
+ * caller needs to cast result to either
+ * raw = yes: struct gpfs_opaque_acl
+ * raw = no: struct gpfs_acl
+ *
+ */
+static void *vfs_gpfs_getacl(TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const bool raw,
+ const gpfs_aclType_t type)
+{
+
+ void *aclbuf;
+ size_t size = 512;
+ int ret, flags;
+ unsigned int *len;
+ size_t struct_size;
+
+again:
+
+ aclbuf = talloc_zero_size(mem_ctx, size);
+ if (aclbuf == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (raw) {
+ struct gpfs_opaque_acl *buf = (struct gpfs_opaque_acl *) aclbuf;
+ buf->acl_type = type;
+ flags = GPFS_GETACL_NATIVE;
+ len = (unsigned int *) &(buf->acl_buffer_len);
+ struct_size = sizeof(struct gpfs_opaque_acl);
+ } else {
+ struct gpfs_acl *buf = (struct gpfs_acl *) aclbuf;
+ buf->acl_type = type;
+ flags = GPFS_GETACL_STRUCT;
+ len = &(buf->acl_len);
+ struct_size = sizeof(struct gpfs_acl);
+ }
+
+ /* set the length of the buffer as input value */
+ *len = size;
+
+ errno = 0;
+ ret = smbd_gpfs_getacl((char *)fname, flags, aclbuf);
+ if ((ret != 0) && (errno == ENOSPC)) {
+ /*
+ * get the size needed to accommodate the complete buffer
+ *
+ * the value returned only applies to the ACL blob in the
+ * struct so make sure to also have headroom for the first
+ * struct members by adding room for the complete struct
+ * (might be a few bytes too much then)
+ */
+ size = *len + struct_size;
+ talloc_free(aclbuf);
+ DEBUG(10, ("Increasing ACL buffer size to %zu\n", size));
+ goto again;
+ }
+
+ if (ret != 0) {
+ DEBUG(5, ("smbd_gpfs_getacl failed with %s\n",
+ strerror(errno)));
+ talloc_free(aclbuf);
+ return NULL;
+ }
+
+ return aclbuf;
+}
+
static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
{
struct gpfs_acl *acl;
struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
if (new_acl == NULL) {
+ talloc_free(acl);
errno = ENOMEM;
return NULL;
}
new_acl->acl_level = acl->acl_level;
new_acl->acl_version = acl->acl_version;
new_acl->acl_type = acl->acl_type;
+ talloc_free(acl);
acl = new_acl;
ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT, acl);
}
- if (ret != 0)
- {
+ if (ret != 0) {
DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
+ talloc_free(acl);
return NULL;
}
if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
DEBUG(10, ("Got non-nfsv4 acl\n"));
/* Retry with POSIX ACLs check */
+ talloc_free(gacl);
return 1;
}
static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
files_struct *fsp, uint32 security_info,
+ TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc)
{
SMB4ACL_T *pacl = NULL;
return NT_STATUS_INTERNAL_ERROR);
if (!config->acl) {
- return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc);
+ return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
+ mem_ctx, ppdesc);
}
result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
if (result == 0)
- return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+ return smb_fget_nt_acl_nfs4(fsp, security_info, mem_ctx, ppdesc, pacl);
if (result > 0) {
DEBUG(10, ("retrying with posix acl...\n"));
- return posix_fget_nt_acl(fsp, security_info, ppdesc);
+ return posix_fget_nt_acl(fsp, security_info, mem_ctx, ppdesc);
}
/* GPFS ACL was not read, something wrong happened, error code is set in errno */
static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
const char *name,
- uint32 security_info, struct security_descriptor **ppdesc)
+ uint32 security_info,
+ TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc)
{
SMB4ACL_T *pacl = NULL;
int result;
return NT_STATUS_INTERNAL_ERROR);
if (!config->acl) {
- return SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc);
+ return SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
+ mem_ctx, ppdesc);
}
result = gpfs_get_nfs4_acl(name, &pacl);
if (result == 0)
- return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info,
+ mem_ctx, ppdesc, pacl);
if (result > 0) {
DEBUG(10, ("retrying with posix acl...\n"));
- return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
+ return posix_get_nt_acl(handle->conn, name, security_info,
+ mem_ctx, ppdesc);
}
/* GPFS ACL was not read, something wrong happened, error code is set in errno */
}
result->count = pacl->acl_nace;
+ result->acl = talloc_realloc(result, result->acl, struct smb_acl_entry,
+ result->count);
+ if (result->acl == NULL) {
+ TALLOC_FREE(result);
+ errno = ENOMEM;
+ return NULL;
+ }
for (i=0; i<pacl->acl_nace; i++) {
struct smb_acl_entry *ace = &result->acl[i];
default:
DEBUG(10, ("Got invalid ace_type: %d\n",
g_ace->ace_type));
- errno = EINVAL;
TALLOC_FREE(result);
+ errno = EINVAL;
return NULL;
}
done:
+ if (pacl != NULL) {
+ talloc_free(pacl);
+ }
if (errno != 0) {
TALLOC_FREE(result);
}
GPFS_ACL_TYPE_ACCESS, mem_ctx);
}
+static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ TALLOC_CTX *mem_ctx,
+ char **blob_description,
+ DATA_BLOB *blob)
+{
+ struct gpfs_config_data *config;
+ struct gpfs_opaque_acl *acl = NULL;
+ DATA_BLOB aclblob;
+ int result;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct gpfs_config_data,
+ return -1);
+
+ if (!config->acl) {
+ return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle, path_p,
+ mem_ctx,
+ blob_description,
+ blob);
+ }
+
+ errno = 0;
+ acl = (struct gpfs_opaque_acl *)
+ vfs_gpfs_getacl(mem_ctx,
+ path_p,
+ true,
+ GPFS_ACL_TYPE_NFS4);
+
+ if (errno) {
+ DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
+ errno, strerror(errno)));
+
+ /* EINVAL means POSIX ACL, bail out on other cases */
+ if (errno != EINVAL) {
+ return -1;
+ }
+ }
+
+ if (acl != NULL) {
+ /*
+ * file has NFSv4 ACL
+ *
+ * we only need the actual ACL blob here
+ * acl_version will always be NFS4 because we asked
+ * for NFS4
+ * acl_type is only used for POSIX ACLs
+ */
+ aclblob.data = (uint8_t*) acl->acl_var_data;
+ aclblob.length = acl->acl_buffer_len;
+
+ *blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
+ if (!*blob_description) {
+ talloc_free(acl);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ result = non_posix_sys_acl_blob_get_file_helper(handle, path_p,
+ aclblob,
+ mem_ctx, blob);
+
+ talloc_free(acl);
+ return result;
+ }
+
+ /* fall back to POSIX ACL */
+ return posix_sys_acl_blob_get_file(handle, path_p, mem_ctx,
+ blob_description, blob);
+}
+
+static int gpfsacl_sys_acl_blob_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ char **blob_description,
+ DATA_BLOB *blob)
+{
+ struct gpfs_config_data *config;
+ struct gpfs_opaque_acl *acl = NULL;
+ DATA_BLOB aclblob;
+ int result;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct gpfs_config_data,
+ return -1);
+
+ if (!config->acl) {
+ return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
+ blob_description, blob);
+ }
+
+ errno = 0;
+ acl = (struct gpfs_opaque_acl *) vfs_gpfs_getacl(mem_ctx,
+ fsp->fsp_name->base_name,
+ true,
+ GPFS_ACL_TYPE_NFS4);
+
+ if (errno) {
+ DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
+ errno, strerror(errno)));
+
+ /* EINVAL means POSIX ACL, bail out on other cases */
+ if (errno != EINVAL) {
+ return -1;
+ }
+ }
+
+ if (acl != NULL) {
+ /*
+ * file has NFSv4 ACL
+ *
+ * we only need the actual ACL blob here
+ * acl_version will always be NFS4 because we asked
+ * for NFS4
+ * acl_type is only used for POSIX ACLs
+ */
+ aclblob.data = (uint8_t*) acl->acl_var_data;
+ aclblob.length = acl->acl_buffer_len;
+
+ *blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
+ if (!*blob_description) {
+ talloc_free(acl);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ result = non_posix_sys_acl_blob_get_fd_helper(handle, fsp,
+ aclblob, mem_ctx,
+ blob);
+
+ talloc_free(acl);
+ return result;
+ }
+
+ /* fall back to POSIX ACL */
+ return posix_sys_acl_blob_get_fd(handle, fsp, mem_ctx,
+ blob_description, blob);
+}
+
static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
SMB_ACL_TYPE_T type)
{
.fset_nt_acl_fn = gpfsacl_fset_nt_acl,
.sys_acl_get_file_fn = gpfsacl_sys_acl_get_file,
.sys_acl_get_fd_fn = gpfsacl_sys_acl_get_fd,
+ .sys_acl_blob_get_file_fn = gpfsacl_sys_acl_blob_get_file,
+ .sys_acl_blob_get_fd_fn = gpfsacl_sys_acl_blob_get_fd,
.sys_acl_set_file_fn = gpfsacl_sys_acl_set_file,
.sys_acl_set_fd_fn = gpfsacl_sys_acl_set_fd,
.sys_acl_delete_def_file_fn = gpfsacl_sys_acl_delete_def_file,