Пример #1
0
static int gpfsacl_emu_chmod(const char *path, mode_t mode)
{
	SMB4ACL_T *pacl = NULL;
	int     result;
	bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
	int     i;
	files_struct    fake_fsp; /* TODO: rationalize parametrization */
	SMB4ACE_T       *smbace;

	DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));

	result = gpfs_get_nfs4_acl(path, &pacl);
	if (result)
		return result;

	if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
		DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
	}

	for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
		SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
		uint32_t        specid = ace->who.special_id;

		if (ace->flags&SMB_ACE4_ID_SPECIAL &&
		    ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
		    specid <= SMB_ACE4_WHO_EVERYONE) {

			uint32_t newMask;

			if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
				haveAllowEntry[specid] = True;

			/* mode >> 6 for @owner, mode >> 3 for @group,
			 * mode >> 0 for @everyone */
			newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
						      mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
			if (ace->aceMask!=newMask) {
				DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
					   path, ace->aceMask, newMask, specid));
			}
			ace->aceMask = newMask;
		}
	}
Пример #2
0
static bool aixjfs2_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
{
	SMB4ACE_T	*smbace;
	TALLOC_CTX	*mem_ctx;
	nfs4_acl_int_t	*jfs2acl;
	int32_t	entryLen;
	uint32	aclLen, naces;
	int	rc;
	acl_type_t	acltype;

	DEBUG(10, ("jfs2_process_smbacl invoked on %s\n", fsp_str_dbg(fsp)));

	/* no need to be freed which is alloced with mem_ctx */
	mem_ctx = talloc_tos();

	entryLen = sizeof(nfs4_ace_int_t);
	if (entryLen & 0x03)
		entryLen = entryLen + 4 - (entryLen%4);

	naces = smb_get_naces(smbacl);
	aclLen = ACL_V4_SIZ + naces * entryLen;
	jfs2acl = (nfs4_acl_int_t *)TALLOC_SIZE(mem_ctx, aclLen);
	if (jfs2acl==NULL) {
		DEBUG(0, ("TALLOC_SIZE failed\n"));
		errno = ENOMEM;
		return False;
	}

	jfs2acl->aclLength = ACL_V4_SIZ;
	jfs2acl->aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
	jfs2acl->aclEntryN = 0;

	for(smbace = smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace))
	{
		SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
		nfs4_ace_int_t *jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2acl) + jfs2acl->aclLength);

		memset(jfs2_ace, 0, entryLen);
		jfs2_ace->entryLen = entryLen; /* won't store textual "who" */
		jfs2_ace->aceType = aceprop->aceType; /* only ACCES|DENY supported by jfs2 */
		jfs2_ace->aceFlags = aceprop->aceFlags;
		jfs2_ace->aceMask = aceprop->aceMask;
		jfs2_ace->flags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_ID_SPECIAL : 0;

		/* don't care it's real content is only 16 or 32 bit */
		jfs2_ace->aceWho.id = aceprop->who.id;

		/* iterate to the next jfs2 ace */
		jfs2acl->aclLength += jfs2_ace->entryLen;
		jfs2acl->aclEntryN++;
	}
	SMB_ASSERT(jfs2acl->aclEntryN==naces);

	/* Don't query it (again) */
	memset(&acltype, 0, sizeof(acl_type_t));
	acltype.u64 = ACL_NFS4;

	/* won't set S_ISUID - the only one JFS2/NFS4 accepts */
	rc = aclx_put(
		fsp->fsp_name->base_name,
		SET_ACL, /* set only the ACL, not mode bits */
		acltype, /* not a pointer !!! */
		jfs2acl,
		jfs2acl->aclLength,
		0 /* don't set here mode bits */
	);
	if (rc) {
		DEBUG(8, ("aclx_put failed with %s\n", strerror(errno)));
		return False;
	}

	DEBUG(10, ("jfs2_process_smbacl succeeded.\n"));
	return True;
}
Пример #3
0
/*
 * Because there is no good way to guarantee that a new xattr will be
 * created on file creation there might be no acl xattr on a file when
 * trying to read the acl. In this case the acl xattr will get
 * constructed at that time from the parent acl.
 * If the parent ACL doesn't have an xattr either the call will
 * recurse to the next parent directory until the share root is
 * reached. If the share root doesn't contain an ACL xattr either a
 * default ACL will be used.
 * Also a default ACL will be set if a non inheriting ACL is encountered.
 *
 * Basic algorithm:
 *   read acl xattr blob
 *   if acl xattr blob doesn't exist
 *     stat current directory to know if it's a file or directory
 *     read acl xattr blob from parent dir
 *     acl xattr blob to smb nfs4 acl
 *     calculate inherited smb nfs4 acl
 *     without inheritance use default smb nfs4 acl
 *     smb nfs4 acl to acl xattr blob
 *     set acl xattr blob
 *     return smb nfs4 acl
 *   else
 *     acl xattr blob to smb nfs4 acl
 *
 * Todo: Really use mem_ctx after fixing interface of nfs4_acls
 */
static struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
	const char *path,
	TALLOC_CTX *mem_ctx)
{
	char *parent_dir = NULL;
	struct SMB4ACL_T *pparentacl = NULL;
	struct SMB4ACL_T *pchildacl = NULL;
	struct SMB4ACE_T *pace;
	SMB_ACE4PROP_T ace;
	bool isdir;
	struct smb_filename *smb_fname = NULL;
	NTSTATUS status;
	int ret;
	TALLOC_CTX *frame = talloc_stackframe();

	DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n", path));
	smb_fname = synthetic_smb_fname(frame, path, NULL, NULL);
	if (smb_fname == NULL) {
		TALLOC_FREE(frame);
		errno = ENOMEM;
		return NULL;
	}

	ret = SMB_VFS_STAT(handle->conn, smb_fname);
	if (ret == -1) {
		DEBUG(0,("nfs4acls_inheritacl: failed to stat "
			 "directory %s. Error was %s\n",
			 smb_fname_str_dbg(smb_fname),
			 strerror(errno)));
		TALLOC_FREE(frame);
		return NULL;
	}
	isdir = S_ISDIR(smb_fname->st.st_ex_mode);

	if (!parent_dirname(talloc_tos(),
			    path,
			    &parent_dir,
			    NULL)) {
		TALLOC_FREE(frame);
		errno = ENOMEM;
		return NULL;
	}

	status = nfs4_get_nfs4_acl(handle, frame, parent_dir, &pparentacl);
	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)
	    && strncmp(parent_dir, ".", 2) != 0) {
		pparentacl = nfs4acls_inheritacl(handle, parent_dir,
						 frame);
	}
	else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
		pparentacl = nfs4acls_defaultacl(frame);

	}
	else if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(frame);
		return NULL;
	}

	pchildacl = smb_create_smb4acl(mem_ctx);
	if (pchildacl == NULL) {
		DEBUG(0, ("talloc failed\n"));
		TALLOC_FREE(frame);
		errno = ENOMEM;
		return NULL;
	}

	for (pace = smb_first_ace4(pparentacl); pace != NULL;
	     pace = smb_next_ace4(pace)) {
		struct SMB4ACE_T *pchildace;
		ace = *smb_get_ace4(pace);
		if ((isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) ||
		    (!isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))) {
			DEBUG(10, ("non inheriting ace type: %d, iflags: %x, "
				   "flags: %x, mask: %x, who: %d\n",
				   ace.aceType, ace.flags, ace.aceFlags,
				   ace.aceMask, ace.who.id));
			continue;
		}
		DEBUG(10, ("inheriting ace type: %d, iflags: %x, "
			   "flags: %x, mask: %x, who: %d\n",
			   ace.aceType, ace.flags, ace.aceFlags,
			   ace.aceMask, ace.who.id));
		ace.aceFlags |= SMB_ACE4_INHERITED_ACE;
		if (ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) {
			ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE;
		}
		if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) {
			ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE;
			ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE;
			ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE;
		}
		pchildace = smb_add_ace4(pchildacl, &ace);
		if (pchildace == NULL) {
			DEBUG(0, ("talloc failed\n"));
			TALLOC_FREE(frame);
			errno = ENOMEM;
			return NULL;
		}
	}

	/* Set a default ACL if we didn't inherit anything. */
	if (smb_first_ace4(pchildacl) == NULL) {
		TALLOC_FREE(pchildacl);
		pchildacl = nfs4acls_defaultacl(mem_ctx);
	}

	/* store the returned ACL to get it directly in the
	   future and avoid dynamic inheritance behavior. */
	nfs4acl_xattr_set_smb4acl(handle, path, pchildacl);

	TALLOC_FREE(frame);
	return pchildacl;
}
Пример #4
0
static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
				    struct SMB4ACL_T *smbacl,
				    struct nfs4acl **pnfs4acl,
				    bool denymissingspecial)
{
	struct nfs4acl *nfs4acl;
	struct SMB4ACE_T *smbace;
	bool have_special_id = false;
	int i;

	/* allocate the field of NFS4 aces */
	nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
	if(nfs4acl == NULL) {
		errno = ENOMEM;
		return false;
	}

	nfs4acl->a_count = smb_get_naces(smbacl);

	nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
					 nfs4acl->a_count);
	if(nfs4acl->ace == NULL) {
		TALLOC_FREE(nfs4acl);
		errno = ENOMEM;
		return false;
	}

	/* handle all aces */
	for(smbace = smb_first_ace4(smbacl), i = 0;
			smbace!=NULL;
			smbace = smb_next_ace4(smbace), i++) {
		SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);

		nfs4acl->ace[i].e_type        = aceprop->aceType;
		nfs4acl->ace[i].e_flags       = aceprop->aceFlags;
		nfs4acl->ace[i].e_mask        = aceprop->aceMask;
		nfs4acl->ace[i].e_id          = aceprop->who.id;
		if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
			switch(aceprop->who.special_id) {
			case SMB_ACE4_WHO_EVERYONE:
				nfs4acl->ace[i].e_who =
					NFS4ACL_XATTR_EVERYONE_WHO;
				break;
			case SMB_ACE4_WHO_OWNER:
				nfs4acl->ace[i].e_who =
					NFS4ACL_XATTR_OWNER_WHO;
				break;
			case SMB_ACE4_WHO_GROUP:
				nfs4acl->ace[i].e_who =
					NFS4ACL_XATTR_GROUP_WHO;
				break;
			default:
				DEBUG(8, ("unsupported special_id %d\n", \
					aceprop->who.special_id));
				continue; /* don't add it !!! */
			}
			have_special_id = true;
		} else {
			nfs4acl->ace[i].e_who = "";
		}
	}

	if (!have_special_id && denymissingspecial) {
		TALLOC_FREE(nfs4acl);
		errno = EACCES;
		return false;
	}

	SMB_ASSERT(i == nfs4acl->a_count);

	*pnfs4acl = nfs4acl;
	return true;
}
Пример #5
0
/* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
{
	int naces = smb_get_naces(smbacl), i;
	ace_t *acebuf;
	SMB4ACE_T *smbace;
	TALLOC_CTX	*mem_ctx;
	bool have_special_id = false;

	/* allocate the field of ZFS aces */
	mem_ctx = talloc_tos();
	acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
	if(acebuf == NULL) {
		errno = ENOMEM;
		return False;
	}
	/* handle all aces */
	for(smbace = smb_first_ace4(smbacl), i = 0;
			smbace!=NULL;
			smbace = smb_next_ace4(smbace), i++) {
		SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);

		acebuf[i].a_type        = aceprop->aceType;
		acebuf[i].a_flags       = aceprop->aceFlags;
		acebuf[i].a_access_mask = aceprop->aceMask;
		acebuf[i].a_who         = aceprop->who.id;
		if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
			switch(aceprop->who.special_id) {
			case SMB_ACE4_WHO_EVERYONE:
				acebuf[i].a_flags |= ACE_EVERYONE;
				break;
			case SMB_ACE4_WHO_OWNER:
				acebuf[i].a_flags |= ACE_OWNER;
				break;
			case SMB_ACE4_WHO_GROUP:
				acebuf[i].a_flags |= ACE_GROUP;
				break;
			default:
				DEBUG(8, ("unsupported special_id %d\n", \
					aceprop->who.special_id));
				continue; /* don't add it !!! */
			}
			have_special_id = true;
		}
	}

	if (!have_special_id
	    && lp_parm_bool(fsp->conn->params->service, "zfsacl",
			    "denymissingspecial", false)) {
		errno = EACCES;
		return false;
	}

	SMB_ASSERT(i == naces);

	/* store acl */
	if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) {
		if(errno == ENOSYS) {
			DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
				  "supported on the filesystem where the file "
				  "reside", fsp_str_dbg(fsp)));
		} else {
			DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
				  strerror(errno)));
		}
		return 0;
	}

	return True;
}
Пример #6
0
static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
{
	int ret;
	gpfs_aclLen_t gacl_len;
	SMB4ACE_T	*smbace;
	struct gpfs_acl *gacl;
	TALLOC_CTX *mem_ctx  = talloc_tos();

	gacl_len = sizeof(struct gpfs_acl) +
		(smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);

	gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
	if (gacl == NULL) {
		DEBUG(0, ("talloc failed\n"));
		errno = ENOMEM;
		return False;
	}

	gacl->acl_len = gacl_len;
	gacl->acl_level = 0;
	gacl->acl_version = GPFS_ACL_VERSION_NFS4;
	gacl->acl_type = GPFS_ACL_TYPE_NFS4;
	gacl->acl_nace = 0; /* change later... */

	for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
		struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
		SMB_ACE4PROP_T	*aceprop = smb_get_ace4(smbace);

		gace->aceType = aceprop->aceType;
		gace->aceFlags = aceprop->aceFlags;
		gace->aceMask = aceprop->aceMask;

		/*
		 * GPFS can't distinguish between WRITE and APPEND on
		 * files, so one being set without the other is an
		 * error. Sorry for the many ()'s :-)
		 */

		if (!fsp->is_directory
		    &&
		    ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
		      && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
		     ||
		     (((gace->aceMask & ACE4_MASK_WRITE) != 0)
		      && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
		    &&
		    lp_parm_bool(fsp->conn->params->service, "gpfs",
				 "merge_writeappend", True)) {
			DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
				  "WRITE^APPEND, setting WRITE|APPEND\n",
				  fsp->fsp_name));
			gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
		}

		gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;

		if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
		{
			switch(aceprop->who.special_id)
			{
			case SMB_ACE4_WHO_EVERYONE:
				gace->aceWho = ACE4_SPECIAL_EVERYONE;
				break;
			case SMB_ACE4_WHO_OWNER:
				gace->aceWho = ACE4_SPECIAL_OWNER;
				break;
			case SMB_ACE4_WHO_GROUP:
				gace->aceWho = ACE4_SPECIAL_GROUP;
				break;
			default:
				DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
				continue; /* don't add it !!! */
			}
		} else {
			/* just only for the type safety... */
			if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
				gace->aceWho = aceprop->who.gid;
			else
				gace->aceWho = aceprop->who.uid;
		}

		gacl->acl_nace++;
	}

	ret = smbd_gpfs_putacl(fsp->fsp_name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
	if (ret != 0) {
		DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
		gpfs_dumpacl(8, gacl);
		return False;
	}

	DEBUG(10, ("gpfs_putacl succeeded\n"));
	return True;
}