#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
}
}
+/*
+ * 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;
}
struct gpfs_acl *gacl = NULL;
DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
- /* First get the real acl length */
- gacl = gpfs_getacl_alloc(fname, 0);
+ /* Get the ACL */
+ gacl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(), fname,
+ false, 0);
if (gacl == NULL) {
DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
fname, strerror(errno)));
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;
}
smb_add_ace4(*ppacl, &smbace);
}
+ talloc_free(gacl);
+
return 0;
}
}
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);
}
DATA_BLOB *blob)
{
struct gpfs_config_data *config;
- SMB4ACL_T *pacl = NULL;
+ struct gpfs_opaque_acl *acl = NULL;
+ DATA_BLOB aclblob;
int result;
SMB_VFS_HANDLE_GET_DATA(handle, config,
blob);
}
- result = gpfs_get_nfs4_acl(path_p, &pacl);
- if (result == 0) {
- /* We don't have a way to linearlise the NFS4 ACL
- * right now, and it is much closer to the NT ACL
- * anyway */
- errno = EINVAL;
- return -1;
+ 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);
}
DATA_BLOB *blob)
{
struct gpfs_config_data *config;
- SMB4ACL_T *pacl = NULL;
+ struct gpfs_opaque_acl *acl = NULL;
+ DATA_BLOB aclblob;
int result;
SMB_VFS_HANDLE_GET_DATA(handle, config,
blob_description, blob);
}
- result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
- if (result == 0) {
- /* We don't have a way to linearlise the NFS4 ACL
- * right now, and it is much closer to the NT ACL
- * anyway */
- errno = EINVAL;
- return -1;
+ 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);
}