Blame setcifsacl.c

Packit 5f9837
/*
Packit 5f9837
* setcifsacl utility
Packit 5f9837
*
Packit 5f9837
* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
Packit 5f9837
*
Packit 5f9837
* Used to alter entries of an ACL or replace an entire ACL in a
Packit 5f9837
* security descriptor of a file system object that belongs to a
Packit 5f9837
* share mounted using option cifsacl.
Packit 5f9837
*
Packit 5f9837
* This program is free software; you can redistribute it and/or modify
Packit 5f9837
* it under the terms of the GNU General Public License as published by
Packit 5f9837
* the Free Software Foundation; either version 2 of the License, or
Packit 5f9837
* (at your option) any later version.
Packit 5f9837
* This program is distributed in the hope that it will be useful,
Packit 5f9837
* but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5f9837
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Packit 5f9837
* GNU General Public License for more details.
Packit 5f9837
* You should have received a copy of the GNU General Public License
Packit 5f9837
* along with this program; if not, write to the Free Software
Packit 5f9837
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Packit 5f9837
*/
Packit 5f9837
Packit 5f9837
#ifdef HAVE_CONFIG_H
Packit 5f9837
#include "config.h"
Packit 5f9837
#endif /* HAVE_CONFIG_H */
Packit 5f9837
Packit 5f9837
#include <string.h>
Packit 5f9837
#include <getopt.h>
Packit 5f9837
#include <stdint.h>
Packit 5f9837
#include <stdbool.h>
Packit 5f9837
#include <unistd.h>
Packit 5f9837
#include <stdio.h>
Packit 5f9837
#include <stdlib.h>
Packit 5f9837
#include <errno.h>
Packit 5f9837
#include <limits.h>
Packit 5f9837
#include <ctype.h>
Packit 5f9837
#include <sys/xattr.h>
Packit 5f9837
Packit 5f9837
#include "cifsacl.h"
Packit 5f9837
#include "idmap_plugin.h"
Packit 5f9837
Packit 5f9837
enum setcifsacl_actions {
Packit 5f9837
	ActUnknown = -1,
Packit 5f9837
	ActDelete,
Packit 5f9837
	ActModify,
Packit 5f9837
	ActAdd,
Packit 5f9837
	ActSet
Packit 5f9837
};
Packit 5f9837
Packit 5f9837
static void *plugin_handle;
Packit 5f9837
static bool plugin_loaded;
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
Packit 5f9837
{
Packit 5f9837
	int i, size = 0;
Packit 5f9837
Packit 5f9837
	dst->revision = src->revision;
Packit 5f9837
	size += sizeof(uint8_t);
Packit 5f9837
Packit 5f9837
	dst->num_subauth = src->num_subauth;
Packit 5f9837
	size += sizeof(uint8_t);
Packit 5f9837
Packit 5f9837
	for (i = 0; i < NUM_AUTHS; i++)
Packit 5f9837
		dst->authority[i] = src->authority[i];
Packit 5f9837
	size += (sizeof(uint8_t) * NUM_AUTHS);
Packit 5f9837
Packit 5f9837
	for (i = 0; i < src->num_subauth; i++)
Packit 5f9837
		dst->sub_auth[i] = src->sub_auth[i];
Packit 5f9837
	size += (sizeof(uint32_t) * src->num_subauth);
Packit 5f9837
Packit 5f9837
	return size;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static ssize_t
Packit 5f9837
copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Packit 5f9837
		int numaces, int acessize)
Packit 5f9837
{
Packit 5f9837
	int size, osidsoffset, gsidsoffset, dacloffset;
Packit 5f9837
	ssize_t bufsize;
Packit 5f9837
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Packit 5f9837
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Packit 5f9837
	struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
Packit 5f9837
Packit 5f9837
	/* copy security descriptor control portion */
Packit 5f9837
	osidsoffset = le32toh(pntsd->osidoffset);
Packit 5f9837
	gsidsoffset = le32toh(pntsd->gsidoffset);
Packit 5f9837
	dacloffset = le32toh(pntsd->dacloffset);
Packit 5f9837
Packit 5f9837
	size = sizeof(struct cifs_ntsd);
Packit 5f9837
	pnntsd->revision = pntsd->revision;
Packit 5f9837
	pnntsd->type = pntsd->type;
Packit 5f9837
	pnntsd->osidoffset = pntsd->osidoffset;
Packit 5f9837
	pnntsd->gsidoffset = pntsd->gsidoffset;
Packit 5f9837
	pnntsd->dacloffset = pntsd->dacloffset;
Packit 5f9837
	bufsize = size;
Packit 5f9837
Packit 5f9837
	dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
Packit 5f9837
	ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
Packit 5f9837
Packit 5f9837
	size = acessize + sizeof(struct cifs_ctrl_acl);
Packit 5f9837
	ndacl_ptr->revision = dacl_ptr->revision;
Packit 5f9837
	ndacl_ptr->size = htole16(size);
Packit 5f9837
	ndacl_ptr->num_aces = htole32(numaces);
Packit 5f9837
	bufsize += size;
Packit 5f9837
Packit 5f9837
	/* copy owner sid */
Packit 5f9837
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
Packit Service be8ff3
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
Packit Service be8ff3
	/*
Packit Service be8ff3
	 * some servers like Azure return the owner and group SIDs at end rather
Packit Service be8ff3
	 * than at the beginning of the ACL so don't want to overwrite the last ACEs
Packit Service be8ff3
         */
Packit Service be8ff3
	if (dacloffset <= osidsoffset) {
Packit Service be8ff3
		/* owners placed at end of ACL */
Packit Service be8ff3
		nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + dacloffset + size);
Packit Service be8ff3
		pnntsd->osidoffset = dacloffset + size;
Packit Service be8ff3
		size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
Packit Service be8ff3
		bufsize += size;
Packit Service be8ff3
		/* put group SID after owner SID */
Packit Service be8ff3
		ngroup_sid_ptr = (struct cifs_sid *)((char *)nowner_sid_ptr + size);
Packit Service be8ff3
		pnntsd->gsidoffset = pnntsd->osidoffset + size;
Packit Service be8ff3
	} else {
Packit Service be8ff3
		/*
Packit Service be8ff3
		 * Most servers put the owner information at the beginning,
Packit Service be8ff3
		 * before the ACL
Packit Service be8ff3
		 */
Packit Service be8ff3
		nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
Packit Service be8ff3
		size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
Packit Service be8ff3
		bufsize += size;
Packit Service be8ff3
		ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
Packit Service be8ff3
	}
Packit 5f9837
Packit 5f9837
	/* copy group sid */
Packit 5f9837
	size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
Packit 5f9837
	bufsize += size;
Packit 5f9837
Packit 5f9837
	return bufsize;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
Packit 5f9837
{
Packit 5f9837
	dace->type = sace->type;
Packit 5f9837
	dace->flags = sace->flags;
Packit 5f9837
	dace->access_req = sace->access_req;
Packit 5f9837
Packit 5f9837
	copy_cifs_sid(&dace->sid, &sace->sid);
Packit 5f9837
Packit 5f9837
	dace->size = sace->size;
Packit 5f9837
Packit 5f9837
	return le16toh(dace->size);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
Packit 5f9837
{
Packit 5f9837
	int i;
Packit 5f9837
Packit 5f9837
	if (compflags & COMPSID) {
Packit 5f9837
		if (dace->sid.revision != sace->sid.revision)
Packit 5f9837
			return 0;
Packit 5f9837
		if (dace->sid.num_subauth != sace->sid.num_subauth)
Packit 5f9837
			return 0;
Packit 5f9837
		for (i = 0; i < NUM_AUTHS; i++) {
Packit 5f9837
			if (dace->sid.authority[i] != sace->sid.authority[i])
Packit 5f9837
				return 0;
Packit 5f9837
		}
Packit 5f9837
		for (i = 0; i < sace->sid.num_subauth; i++) {
Packit 5f9837
			if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
Packit 5f9837
				return 0;
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (compflags & COMPTYPE) {
Packit 5f9837
		if (dace->type != sace->type)
Packit 5f9837
			return 0;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (compflags & COMPFLAG) {
Packit 5f9837
		if (dace->flags != sace->flags)
Packit 5f9837
			return 0;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (compflags & COMPMASK) {
Packit 5f9837
		if (dace->access_req != sace->access_req)
Packit 5f9837
			return 0;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return 1;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
alloc_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
Packit 5f9837
			int aces, size_t *acesoffset)
Packit 5f9837
{
Packit 5f9837
	unsigned int size, acessize, bufsize, dacloffset;
Packit 5f9837
Packit 5f9837
	size = sizeof(struct cifs_ntsd) +
Packit 5f9837
		2 * sizeof(struct cifs_sid) +
Packit 5f9837
		sizeof(struct cifs_ctrl_acl);
Packit 5f9837
Packit 5f9837
	dacloffset = le32toh(pntsd->dacloffset);
Packit 5f9837
Packit 5f9837
	*acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
Packit 5f9837
	acessize = aces * sizeof(struct cifs_ace);
Packit 5f9837
	bufsize = size + acessize;
Packit 5f9837
Packit 5f9837
	*npntsd = malloc(bufsize);
Packit 5f9837
	if (!*npntsd) {
Packit 5f9837
		printf("%s: Memory allocation failure", __func__);
Packit 5f9837
		return errno;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
Packit 5f9837
			struct cifs_ace **cacesptr, int numcaces)
Packit 5f9837
{
Packit 5f9837
	int i, rc, size = 0, acessize = 0;
Packit 5f9837
	size_t acesoffset;
Packit 5f9837
	char *acesptr;
Packit 5f9837
Packit 5f9837
	rc = alloc_sec_desc(pntsd, npntsd, numcaces, &acesoffset);
Packit 5f9837
	if (rc)
Packit 5f9837
		return rc;
Packit 5f9837
Packit 5f9837
	acesptr = (char *)*npntsd + acesoffset;
Packit 5f9837
	for (i = 0; i < numcaces; ++i) {
Packit 5f9837
		size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
Packit 5f9837
		acessize += size;
Packit 5f9837
		acesptr += size;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	*bufsize = copy_sec_desc(pntsd, *npntsd, numcaces, acessize);
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
Packit 5f9837
		struct cifs_ace **facesptr, int numfaces,
Packit 5f9837
		struct cifs_ace **cacesptr, int numcaces)
Packit 5f9837
{
Packit 5f9837
	int i, rc, numaces, size, acessize = 0;
Packit 5f9837
	size_t acesoffset;
Packit 5f9837
	char *acesptr;
Packit 5f9837
Packit 5f9837
	numaces = numfaces + numcaces;
Packit 5f9837
	rc = alloc_sec_desc(pntsd, npntsd, numaces, &acesoffset);
Packit 5f9837
	if (rc)
Packit 5f9837
		return rc;
Packit 5f9837
Packit 5f9837
	acesptr = (char *)*npntsd + acesoffset;
Packit 5f9837
	for (i = 0; i < numfaces; ++i) {
Packit 5f9837
		size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
Packit 5f9837
		acesptr += size;
Packit 5f9837
		acessize += size;
Packit 5f9837
	}
Packit 5f9837
	for (i = 0; i < numcaces; ++i) {
Packit 5f9837
		size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
Packit 5f9837
		acesptr += size;
Packit 5f9837
		acessize += size;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	*bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize);
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
Packit 5f9837
		struct cifs_ace **facesptr, int numfaces,
Packit 5f9837
		struct cifs_ace **cacesptr, int numcaces)
Packit 5f9837
{
Packit 5f9837
	int i, j, rc, size, acessize = 0;
Packit 5f9837
	size_t acesoffset;
Packit 5f9837
	char *acesptr;
Packit 5f9837
Packit 5f9837
	if (numfaces == 0) {
Packit 5f9837
		printf("%s: No entries to modify", __func__);
Packit 5f9837
		return -1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset);
Packit 5f9837
	if (rc)
Packit 5f9837
		return rc;
Packit 5f9837
Packit 5f9837
	for (j = 0; j < numcaces; ++j) {
Packit 5f9837
		for (i = 0; i < numfaces; ++i) {
Packit 5f9837
			if (compare_aces(facesptr[i], cacesptr[j],
Packit 5f9837
					COMPSID | COMPTYPE)) {
Packit 5f9837
				copy_ace(facesptr[i], cacesptr[j]);
Packit 5f9837
				break;
Packit 5f9837
			}
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	acesptr = (char *)*npntsd + acesoffset;
Packit 5f9837
	for (i = 0; i < numfaces; ++i) {
Packit 5f9837
		size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
Packit 5f9837
		acesptr += size;
Packit 5f9837
		acessize += size;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	*bufsize = copy_sec_desc(pntsd, *npntsd, numfaces, acessize);
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
Packit 5f9837
		struct cifs_ace **facesptr, int numfaces,
Packit 5f9837
		struct cifs_ace **cacesptr, int numcaces)
Packit 5f9837
{
Packit 5f9837
	int i, j, numaces = 0, rc, size, acessize = 0;
Packit 5f9837
	size_t acesoffset;
Packit 5f9837
	char *acesptr;
Packit 5f9837
Packit 5f9837
	if (numfaces == 0) {
Packit 5f9837
		printf("%s: No entries to delete\n", __func__);
Packit 5f9837
		return -1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (numfaces < numcaces) {
Packit 5f9837
		printf("%s: Invalid entries to delete\n", __func__);
Packit 5f9837
		return -1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset);
Packit 5f9837
	if (rc)
Packit 5f9837
		return rc;
Packit 5f9837
Packit 5f9837
	acesptr = (char *)*npntsd + acesoffset;
Packit 5f9837
	for (i = 0; i < numfaces; ++i) {
Packit 5f9837
		for (j = 0; j < numcaces; ++j) {
Packit 5f9837
			if (compare_aces(facesptr[i], cacesptr[j], COMPALL))
Packit 5f9837
				break;
Packit 5f9837
		}
Packit 5f9837
		if (j == numcaces) {
Packit 5f9837
			size = copy_ace((struct cifs_ace *)acesptr,
Packit 5f9837
								facesptr[i]);
Packit 5f9837
			acessize += size;
Packit 5f9837
			acesptr += size;
Packit 5f9837
			++numaces;
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (numaces == numfaces) {
Packit 5f9837
		printf("%s: Nothing to delete\n", __func__);
Packit 5f9837
		return 1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	*bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize);
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
Packit 5f9837
			struct cifs_ctrl_acl **daclptr)
Packit 5f9837
{
Packit 5f9837
	int numfaces = 0;
Packit 5f9837
	uint32_t dacloffset;
Packit 5f9837
	struct cifs_ctrl_acl *ldaclptr;
Packit 5f9837
	char *end_of_acl = ((char *)pntsd) + acl_len;
Packit 5f9837
Packit 5f9837
	dacloffset = le32toh(pntsd->dacloffset);
Packit 5f9837
	if (!dacloffset)
Packit 5f9837
		return 0;
Packit 5f9837
Packit 5f9837
	ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
Packit 5f9837
Packit 5f9837
	/* validate that we do not go past end of acl */
Packit 5f9837
	if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
Packit 5f9837
		numfaces = le32toh(ldaclptr->num_aces);
Packit 5f9837
		*daclptr = ldaclptr;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return numfaces;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static struct cifs_ace **
Packit 5f9837
build_fetched_aces(char *daclptr, int numfaces)
Packit 5f9837
{
Packit 5f9837
	int i, acl_size;
Packit 5f9837
	char *acl_base;
Packit 5f9837
	struct cifs_ace *pace, **facesptr;
Packit 5f9837
Packit 5f9837
	facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
Packit 5f9837
	if (!facesptr) {
Packit 5f9837
		printf("%s: Error %d allocating ACE array",
Packit 5f9837
				__func__, errno);
Packit 5f9837
		return facesptr;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	acl_base = daclptr;
Packit 5f9837
	acl_size = sizeof(struct cifs_ctrl_acl);
Packit 5f9837
	for (i = 0; i < numfaces; ++i) {
Packit 5f9837
		facesptr[i] = malloc(sizeof(struct cifs_ace));
Packit 5f9837
		if (!facesptr[i])
Packit 5f9837
			goto build_fetched_aces_err;
Packit 5f9837
		pace = (struct cifs_ace *) (acl_base + acl_size);
Packit 5f9837
		memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
Packit 5f9837
		acl_base = (char *)pace;
Packit 5f9837
		acl_size = le16toh(pace->size);
Packit 5f9837
	}
Packit 5f9837
	return facesptr;
Packit 5f9837
Packit 5f9837
build_fetched_aces_err:
Packit 5f9837
	printf("%s: Invalid fetched ace\n", __func__);
Packit 5f9837
	for (i = 0; i < numfaces; ++i)
Packit 5f9837
		free(facesptr[i]);
Packit 5f9837
	free(facesptr);
Packit 5f9837
	return NULL;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
verify_ace_type(char *typestr, uint8_t *typeval)
Packit 5f9837
{
Packit 5f9837
	int i, len;
Packit 5f9837
	char *invaltype;
Packit 5f9837
Packit 5f9837
	if (strstr(typestr, "0x")) { /* hex type value */
Packit 5f9837
		*typeval = strtol(typestr, &invaltype, 16);
Packit 5f9837
		if (!strlen(invaltype)) {
Packit 5f9837
			if (*typeval != ACCESS_ALLOWED &&
Packit 5f9837
				*typeval != ACCESS_DENIED &&
Packit 5f9837
				*typeval != ACCESS_ALLOWED_OBJECT &&
Packit 5f9837
				*typeval != ACCESS_DENIED_OBJECT) {
Packit 5f9837
					printf("%s: Invalid type: %s\n",
Packit 5f9837
						__func__, typestr);
Packit 5f9837
					return 1;
Packit 5f9837
			}
Packit 5f9837
			return 0;
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	len = strlen(typestr);
Packit 5f9837
	for (i = 0; i < len; ++i)
Packit 5f9837
		*(typestr + i) = toupper(*(typestr + i));
Packit 5f9837
	if (!strcmp(typestr, "ALLOWED"))
Packit 5f9837
		*typeval = 0x0;
Packit 5f9837
	else if (!strcmp(typestr, "DENIED"))
Packit 5f9837
		*typeval = 0x1;
Packit 5f9837
	else if (!strcmp(typestr, "ALLOWED_OBJECT"))
Packit 5f9837
		*typeval = 0x5;
Packit 5f9837
	else if (!strcmp(typestr, "DENIED_OBJECT"))
Packit 5f9837
		*typeval = 0x6;
Packit 5f9837
	else {
Packit 5f9837
		printf("%s: Invalid type: %s\n", __func__, typestr);
Packit 5f9837
		return 1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static uint8_t
Packit 5f9837
ace_flag_value(char *flagstr)
Packit 5f9837
{
Packit 5f9837
	uint8_t flagval = 0x0;
Packit 5f9837
	char *iflag;
Packit 5f9837
Packit 5f9837
	iflag = strtok(flagstr, "|"); /* everything before | */
Packit 5f9837
	while (iflag) {
Packit 5f9837
		if (!strcmp(iflag, "OI"))
Packit 5f9837
			flagval += 0x1;
Packit 5f9837
		else if (!strcmp(iflag, "CI"))
Packit 5f9837
			flagval += 0x2;
Packit 5f9837
		else if (!strcmp(iflag, "NP"))
Packit 5f9837
			flagval += 0x4;
Packit 5f9837
		else if (!strcmp(iflag, "IO"))
Packit 5f9837
			flagval += 0x8;
Packit 5f9837
		else if (!strcmp(iflag, "I"))
Packit 5f9837
			flagval += 0x10;
Packit 5f9837
		else
Packit 5f9837
			return 0x0; /* Invalid flag */
Packit 5f9837
		iflag = strtok(NULL, "|"); /* everything before | */
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return flagval;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
verify_ace_flags(char *flagstr, uint8_t *flagval)
Packit 5f9837
{
Packit 5f9837
	char *invalflag;
Packit 5f9837
Packit 5f9837
	if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
Packit 5f9837
		return 0;
Packit 5f9837
Packit 5f9837
	if (strstr(flagstr, "0x")) { /* hex flag value */
Packit 5f9837
		*flagval = strtol(flagstr, &invalflag, 16);
Packit 5f9837
		if (strlen(invalflag)) {
Packit 5f9837
			printf("%s: Invalid flags: %s\n", __func__, flagstr);
Packit 5f9837
			return 1;
Packit 5f9837
		}
Packit 5f9837
	} else
Packit 5f9837
		*flagval = ace_flag_value(flagstr);
Packit 5f9837
Packit 5f9837
	if (!*flagval || (*flagval & ~VFLAGS)) {
Packit 5f9837
		printf("%s: Invalid flag %s and value: 0x%x\n",
Packit 5f9837
			__func__, flagstr, *flagval);
Packit 5f9837
		return 1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static uint32_t
Packit 5f9837
ace_mask_value(char *mask)
Packit 5f9837
{
Packit 5f9837
	uint32_t maskval = 0;
Packit 5f9837
	char cur;
Packit 5f9837
Packit 5f9837
	if (!strcmp(mask, "FULL"))
Packit 5f9837
		return FULL_CONTROL;
Packit 5f9837
	if (!strcmp(mask, "CHANGE"))
Packit 5f9837
		return CHANGE;
Packit 5f9837
	if (!strcmp(mask, "READ"))
Packit 5f9837
		return EREAD;
Packit 5f9837
Packit 5f9837
	while((cur = *mask++)) {
Packit 5f9837
		switch(cur) {
Packit 5f9837
		case 'R':
Packit 5f9837
			maskval |= EREAD;
Packit 5f9837
			break;
Packit 5f9837
		case 'W':
Packit 5f9837
			maskval |= EWRITE;
Packit 5f9837
			break;
Packit 5f9837
		case 'X':
Packit 5f9837
			maskval |= EXEC;
Packit 5f9837
			break;
Packit 5f9837
		case 'D':
Packit 5f9837
			maskval |= DELETE;
Packit 5f9837
			break;
Packit 5f9837
		case 'P':
Packit 5f9837
			maskval |= WRITE_DAC;
Packit 5f9837
			break;
Packit 5f9837
		case 'O':
Packit 5f9837
			maskval |= WRITE_OWNER;
Packit 5f9837
			break;
Packit 5f9837
		default:
Packit 5f9837
			return 0;
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
	return maskval;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
verify_ace_mask(char *maskstr, uint32_t *maskval)
Packit 5f9837
{
Packit 5f9837
	unsigned long val;
Packit 5f9837
	char *ep;
Packit 5f9837
Packit 5f9837
	errno = 0;
Packit 5f9837
	val = strtoul(maskstr, &ep, 0);
Packit 5f9837
	if (errno == 0 && *ep == '\0')
Packit 5f9837
		*maskval = htole32((uint32_t)val);
Packit 5f9837
	else
Packit 5f9837
		*maskval = htole32(ace_mask_value(maskstr));
Packit 5f9837
Packit 5f9837
	if (!*maskval) {
Packit 5f9837
		printf("%s: Invalid mask %s (value 0x%x)\n", __func__,
Packit 5f9837
			maskstr, *maskval);
Packit 5f9837
		return 1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
#define AUTHORITY_MASK (~(0xffffffffffffULL))
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
raw_str_to_sid(const char *str, struct cifs_sid *csid)
Packit 5f9837
{
Packit 5f9837
	const char *p;
Packit 5f9837
	char *q;
Packit 5f9837
	unsigned long long x;
Packit 5f9837
Packit 5f9837
	/* Sanity check for either "S-" or "s-" */
Packit 5f9837
	if ((str[0] != 'S' && str[0] != 's') || (str[1]!='-')) {
Packit 5f9837
		plugin_errmsg = "SID string does not start with \"S-\"";
Packit 5f9837
		return -EINVAL;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* Get the SID revision number */
Packit 5f9837
	p = str + 2;
Packit 5f9837
	x = strtoull(p, &q, 10);
Packit 5f9837
	if (x == 0 || x > UCHAR_MAX || !q || *q != '-') {
Packit 5f9837
		plugin_errmsg = "Invalid SID revision number";
Packit 5f9837
		return -EINVAL;
Packit 5f9837
	}
Packit 5f9837
	csid->revision = (uint8_t)x;
Packit 5f9837
Packit 5f9837
	/*
Packit 5f9837
	 * Next the Identifier Authority. This is stored in big-endian in a
Packit 5f9837
	 * 6 byte array. If the authority value is > UINT_MAX, then it should
Packit 5f9837
	 * be expressed as a hex value.
Packit 5f9837
	 */
Packit 5f9837
	p = q + 1;
Packit 5f9837
	x = strtoull(p, &q, 0);
Packit 5f9837
	if ((x & AUTHORITY_MASK) || !q || *q !='-') {
Packit 5f9837
		plugin_errmsg = "Invalid SID authority";
Packit 5f9837
		return -EINVAL;
Packit 5f9837
	}
Packit 5f9837
	csid->authority[5] = (x & 0x0000000000ffULL);
Packit 5f9837
	csid->authority[4] = (x & 0x00000000ff00ULL) >> 8;
Packit 5f9837
	csid->authority[3] = (x & 0x000000ff0000ULL) >> 16;
Packit 5f9837
	csid->authority[2] = (x & 0x0000ff000000ULL) >> 24;
Packit 5f9837
	csid->authority[1] = (x & 0x00ff00000000ULL) >> 32;
Packit 5f9837
	csid->authority[0] = (x & 0xff0000000000ULL) >> 40;
Packit 5f9837
Packit 5f9837
	/* now read the the subauthorities and store as __le32 vals */
Packit 5f9837
	p = q + 1;
Packit 5f9837
	csid->num_subauth = 0;
Packit 5f9837
	while (csid->num_subauth < SID_MAX_SUB_AUTHORITIES) {
Packit 5f9837
		x = strtoul(p, &q, 10);
Packit 5f9837
		if (p == q)
Packit 5f9837
			break;
Packit 5f9837
		if (x > UINT_MAX) {
Packit 5f9837
			plugin_errmsg = "Invalid sub authority value";
Packit 5f9837
			return -EINVAL;
Packit 5f9837
		}
Packit 5f9837
		csid->sub_auth[csid->num_subauth++] = htole32((uint32_t)x);
Packit 5f9837
Packit 5f9837
		if (*q != '-')
Packit 5f9837
			break;
Packit 5f9837
		p = q + 1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* IF we ended early, then the SID could not be converted */
Packit 5f9837
	if (q && *q != '\0') {
Packit 5f9837
		plugin_errmsg = "Invalid sub authority value";
Packit 5f9837
		return -EINVAL;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
setcifsacl_str_to_sid(const char *str, struct cifs_sid *sid)
Packit 5f9837
{
Packit 5f9837
	if (plugin_loaded)
Packit 5f9837
		return str_to_sid(plugin_handle, str, sid);
Packit 5f9837
	return raw_str_to_sid(str, sid);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static struct cifs_ace **
Packit 5f9837
build_cmdline_aces(char **arrptr, int numcaces)
Packit 5f9837
{
Packit 5f9837
	int i;
Packit 5f9837
	char *acesid, *acetype, *aceflag, *acemask;
Packit 5f9837
	struct cifs_ace **cacesptr;
Packit 5f9837
Packit 5f9837
	cacesptr = calloc(numcaces, sizeof(struct cifs_aces *));
Packit 5f9837
	if (!cacesptr) {
Packit 5f9837
		printf("%s: Error %d allocating ACE array", __func__, errno);
Packit 5f9837
		return NULL;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	for (i = 0; i < numcaces; ++i) {
Packit 5f9837
		acesid = strtok(arrptr[i], ":");
Packit 5f9837
		acetype = strtok(NULL, "/");
Packit 5f9837
		aceflag = strtok(NULL, "/");
Packit 5f9837
		acemask = strtok(NULL, "/");
Packit 5f9837
Packit 5f9837
		if (!acesid || !acetype || !aceflag || !acemask) {
Packit 5f9837
			printf("%s: Incomplete ACE: %s\n", __func__, arrptr[i]);
Packit 5f9837
			goto build_cmdline_aces_ret;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		cacesptr[i] = malloc(sizeof(struct cifs_ace));
Packit 5f9837
		if (!cacesptr[i]) {
Packit 5f9837
			printf("%s: ACE alloc error %d\n", __func__, errno);
Packit 5f9837
			goto build_cmdline_aces_ret;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		if (setcifsacl_str_to_sid(acesid, &cacesptr[i]->sid)) {
Packit 5f9837
			printf("%s: Invalid SID (%s): %s\n", __func__, arrptr[i],
Packit 5f9837
				plugin_errmsg);
Packit 5f9837
			goto build_cmdline_aces_ret;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		if (verify_ace_type(acetype, &cacesptr[i]->type)) {
Packit 5f9837
			printf("%s: Invalid ACE type: %s\n",
Packit 5f9837
					__func__, arrptr[i]);
Packit 5f9837
			goto build_cmdline_aces_ret;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		if (verify_ace_flags(aceflag, &cacesptr[i]->flags)) {
Packit 5f9837
			printf("%s: Invalid ACE flag: %s\n",
Packit 5f9837
				__func__, arrptr[i]);
Packit 5f9837
			goto build_cmdline_aces_ret;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
Packit 5f9837
			printf("%s: Invalid ACE mask: %s\n",
Packit 5f9837
				__func__, arrptr[i]);
Packit 5f9837
			goto build_cmdline_aces_ret;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		cacesptr[i]->size = htole16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
Packit 5f9837
					    cacesptr[i]->sid.num_subauth * 4);
Packit 5f9837
	}
Packit 5f9837
	return cacesptr;
Packit 5f9837
Packit 5f9837
build_cmdline_aces_ret:
Packit 5f9837
	for (i = 0; i < numcaces; ++i)
Packit 5f9837
		free(cacesptr[i]);
Packit 5f9837
	free(cacesptr);
Packit 5f9837
	return NULL;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static char **
Packit 5f9837
parse_cmdline_aces(char *acelist, int numcaces)
Packit 5f9837
{
Packit 5f9837
	int i = 0;
Packit 5f9837
	char *acestr, *vacestr, **arrptr = NULL;
Packit 5f9837
Packit 5f9837
	arrptr = (char **)malloc(numcaces * sizeof(char *));
Packit 5f9837
	if (!arrptr) {
Packit 5f9837
		printf("%s: Unable to allocate char array\n", __func__);
Packit 5f9837
		return NULL;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	while (i < numcaces) {
Packit 5f9837
		acestr = strtok(acelist, ","); /* everything before , */
Packit 5f9837
		if (!acestr)
Packit 5f9837
			goto parse_cmdline_aces_err;
Packit 5f9837
Packit 5f9837
		vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
Packit 5f9837
		if (!vacestr)
Packit 5f9837
			goto parse_cmdline_aces_err;
Packit 5f9837
		vacestr += 4; /* skip past "ACL:" */
Packit 5f9837
		if (*vacestr) {
Packit 5f9837
			arrptr[i] = vacestr;
Packit 5f9837
			++i;
Packit 5f9837
		}
Packit 5f9837
		acelist = NULL;
Packit 5f9837
	}
Packit 5f9837
	return arrptr;
Packit 5f9837
Packit 5f9837
parse_cmdline_aces_err:
Packit 5f9837
	printf("%s: Error parsing ACEs\n", __func__);
Packit 5f9837
	free(arrptr);
Packit 5f9837
	return NULL;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* How many aces were provided on the command-line? Count the commas. */
Packit 5f9837
static unsigned int
Packit 5f9837
get_numcaces(const char *aces)
Packit 5f9837
{
Packit 5f9837
	unsigned int num = 1;
Packit 5f9837
	const char *current;
Packit 5f9837
Packit 5f9837
	current = aces;
Packit 5f9837
	while((current = strchr(current, ','))) {
Packit 5f9837
		++current;
Packit 5f9837
		++num;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return num;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
Packit 5f9837
		ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
Packit 5f9837
		struct cifs_ace **cacesptr, int numcaces,
Packit 5f9837
		enum setcifsacl_actions maction)
Packit 5f9837
{
Packit 5f9837
	int rc = 1;
Packit 5f9837
Packit 5f9837
	switch (maction) {
Packit 5f9837
	case ActDelete:
Packit 5f9837
		rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
Packit 5f9837
				numfaces, cacesptr, numcaces);
Packit 5f9837
		break;
Packit 5f9837
	case ActModify:
Packit 5f9837
		rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
Packit 5f9837
				numfaces, cacesptr, numcaces);
Packit 5f9837
		break;
Packit 5f9837
	case ActAdd:
Packit 5f9837
		rc = ace_add(pntsd, npntsd, bufsize, facesptr,
Packit 5f9837
				numfaces, cacesptr, numcaces);
Packit 5f9837
		break;
Packit 5f9837
	case ActSet:
Packit 5f9837
		rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
Packit 5f9837
		break;
Packit 5f9837
	default:
Packit 5f9837
		printf("%s: Invalid action: %d\n", __func__, maction);
Packit 5f9837
		break;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return rc;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static void
Packit 5f9837
setcifsacl_usage(const char *prog)
Packit 5f9837
{
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
Packit 5f9837
		prog);
Packit 5f9837
	fprintf(stderr, "Usage: %s option <list_of_ACEs> <file_name>\n", prog);
Packit 5f9837
	fprintf(stderr, "Valid options:\n");
Packit 5f9837
	fprintf(stderr, "\t-v	Version of the program\n");
Packit 5f9837
	fprintf(stderr, "\n\t-a	Add ACE(s), separated by a comma, to an ACL\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
Packit 5f9837
	fprintf(stderr, "\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\t-D	Delete ACE(s), separated by a comma, from an ACL\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
Packit 5f9837
	fprintf(stderr, "\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\t-M	Modify ACE(s), separated by a comma, in an ACL\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\n\t-S	Replace existing ACL with ACE(s), separated by a comma\n");
Packit 5f9837
	fprintf(stderr,
Packit 5f9837
	"\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
Packit 5f9837
	fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
int
Packit 5f9837
main(const int argc, char *const argv[])
Packit 5f9837
{
Packit 5f9837
	int i, rc, c, numcaces, numfaces;
Packit 5f9837
	enum setcifsacl_actions maction = ActUnknown;
Packit 5f9837
	ssize_t attrlen, bufsize = BUFSIZE;
Packit 5f9837
	char *ace_list, *filename, *attrval, **arrptr = NULL;
Packit 5f9837
	struct cifs_ctrl_acl *daclptr = NULL;
Packit 5f9837
	struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
Packit 5f9837
	struct cifs_ntsd *ntsdptr = NULL;
Packit 5f9837
Packit 5f9837
	c = getopt(argc, argv, "hvD:M:a:S:");
Packit 5f9837
	switch (c) {
Packit 5f9837
	case 'D':
Packit 5f9837
		maction = ActDelete;
Packit 5f9837
		ace_list = optarg;
Packit 5f9837
		break;
Packit 5f9837
	case 'M':
Packit 5f9837
		maction = ActModify;
Packit 5f9837
		ace_list = optarg;
Packit 5f9837
		break;
Packit 5f9837
	case 'a':
Packit 5f9837
		maction = ActAdd;
Packit 5f9837
		ace_list = optarg;
Packit 5f9837
		break;
Packit 5f9837
	case 'S':
Packit 5f9837
		maction = ActSet;
Packit 5f9837
		ace_list = optarg;
Packit 5f9837
		break;
Packit 5f9837
	case 'h':
Packit 5f9837
		setcifsacl_usage(basename(argv[0]));
Packit 5f9837
		return 0;
Packit 5f9837
	case 'v':
Packit 5f9837
		printf("Version: %s\n", VERSION);
Packit 5f9837
		return 0;
Packit 5f9837
	default:
Packit 5f9837
		setcifsacl_usage(basename(argv[0]));
Packit 5f9837
		return -1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* We expect 1 argument in addition to the option */
Packit 5f9837
	if (argc != 4) {
Packit 5f9837
		setcifsacl_usage(basename(argv[0]));
Packit 5f9837
		return -1;
Packit 5f9837
	}
Packit 5f9837
	filename = argv[3];
Packit 5f9837
Packit 5f9837
	if (!ace_list) {
Packit 5f9837
		printf("%s: No valid ACEs specified\n", __func__);
Packit 5f9837
		return -1;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (init_plugin(&plugin_handle)) {
Packit 5f9837
		fprintf(stderr, "WARNING: unable to initialize idmapping "
Packit 5f9837
				"plugin. Only \"raw\" SID strings will be "
Packit 5f9837
				"accepted: %s\n", plugin_errmsg);
Packit 5f9837
		plugin_loaded = false;
Packit 5f9837
	} else {
Packit 5f9837
		plugin_loaded = true;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	numcaces = get_numcaces(ace_list);
Packit 5f9837
Packit 5f9837
	arrptr = parse_cmdline_aces(ace_list, numcaces);
Packit 5f9837
	if (!arrptr)
Packit 5f9837
		goto setcifsacl_numcaces_ret;
Packit 5f9837
Packit 5f9837
	cacesptr = build_cmdline_aces(arrptr, numcaces);
Packit 5f9837
	if (!cacesptr)
Packit 5f9837
		goto setcifsacl_cmdlineparse_ret;
Packit 5f9837
Packit 5f9837
cifsacl:
Packit 5f9837
	if (bufsize >= XATTR_SIZE_MAX) {
Packit 5f9837
		printf("%s: Buffer size %zd exceeds max size of %d\n",
Packit 5f9837
				__func__, bufsize, XATTR_SIZE_MAX);
Packit 5f9837
		goto setcifsacl_cmdlineverify_ret;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	attrval = malloc(bufsize * sizeof(char));
Packit 5f9837
	if (!attrval) {
Packit 5f9837
		printf("error allocating memory for attribute value buffer\n");
Packit 5f9837
		goto setcifsacl_cmdlineverify_ret;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
Packit 5f9837
	if (attrlen == -1) {
Packit 5f9837
		if (errno == ERANGE) {
Packit 5f9837
			free(attrval);
Packit 5f9837
			bufsize += BUFSIZE;
Packit 5f9837
			goto cifsacl;
Packit 5f9837
		} else {
Packit 5f9837
			printf("getxattr error: %d\n", errno);
Packit 5f9837
			goto setcifsacl_getx_ret;
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
Packit 5f9837
	if (!numfaces && maction != ActAdd) { /* if we are not adding aces */
Packit 5f9837
		printf("%s: Empty DACL\n", __func__);
Packit 5f9837
		goto setcifsacl_facenum_ret;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	facesptr = build_fetched_aces((char *)daclptr, numfaces);
Packit 5f9837
	if (!facesptr)
Packit 5f9837
		goto setcifsacl_facenum_ret;
Packit 5f9837
Packit 5f9837
	bufsize = 0;
Packit 5f9837
	rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
Packit 5f9837
		facesptr, numfaces, cacesptr, numcaces, maction);
Packit 5f9837
	if (rc)
Packit 5f9837
		goto setcifsacl_action_ret;
Packit 5f9837
Packit 5f9837
	attrlen = setxattr(filename, ATTRNAME, ntsdptr, bufsize, 0);
Packit 5f9837
	if (attrlen == -1) {
Packit 5f9837
		printf("%s: setxattr error: %s\n", __func__, strerror(errno));
Packit 5f9837
		goto setcifsacl_facenum_ret;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (plugin_loaded)
Packit 5f9837
		exit_plugin(plugin_handle);
Packit 5f9837
	return 0;
Packit 5f9837
Packit 5f9837
setcifsacl_action_ret:
Packit 5f9837
	free(ntsdptr);
Packit 5f9837
Packit 5f9837
setcifsacl_facenum_ret:
Packit 5f9837
	for (i = 0; i < numfaces; ++i)
Packit 5f9837
		free(facesptr[i]);
Packit 5f9837
	free(facesptr);
Packit 5f9837
Packit 5f9837
setcifsacl_getx_ret:
Packit 5f9837
	free(attrval);
Packit 5f9837
Packit 5f9837
setcifsacl_cmdlineverify_ret:
Packit 5f9837
	for (i = 0; i < numcaces; ++i)
Packit 5f9837
		free(cacesptr[i]);
Packit 5f9837
	free(cacesptr);
Packit 5f9837
Packit 5f9837
setcifsacl_cmdlineparse_ret:
Packit 5f9837
	free(arrptr);
Packit 5f9837
Packit 5f9837
setcifsacl_numcaces_ret:
Packit 5f9837
	exit_plugin(plugin_handle);
Packit 5f9837
	return -1;
Packit 5f9837
}