Blame getcifsacl.c

Packit Service 09cdfc
/*
Packit Service 09cdfc
* getcifsacl utility
Packit Service 09cdfc
*
Packit Service 09cdfc
* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
Packit Service 09cdfc
*
Packit Service 09cdfc
* Used to display a security descriptor including ACL of a file object
Packit Service 09cdfc
* that belongs to a share mounted using option cifsacl.
Packit Service 09cdfc
*
Packit Service 09cdfc
* This program is free software; you can redistribute it and/or modify
Packit Service 09cdfc
* it under the terms of the GNU General Public License as published by
Packit Service 09cdfc
* the Free Software Foundation; either version 2 of the License, or
Packit Service 09cdfc
* (at your option) any later version.
Packit Service 09cdfc
* This program is distributed in the hope that it will be useful,
Packit Service 09cdfc
* but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 09cdfc
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Packit Service 09cdfc
* GNU General Public License for more details.
Packit Service 09cdfc
* You should have received a copy of the GNU General Public License
Packit Service 09cdfc
* along with this program; if not, write to the Free Software
Packit Service 09cdfc
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Packit Service 09cdfc
*/
Packit Service 09cdfc
Packit Service 09cdfc
#ifdef HAVE_CONFIG_H
Packit Service 09cdfc
#include "config.h"
Packit Service 09cdfc
#endif /* HAVE_CONFIG_H */
Packit Service 09cdfc
Packit Service 09cdfc
#include <string.h>
Packit Service 09cdfc
#include <getopt.h>
Packit Service 09cdfc
#include <stdint.h>
Packit Service 09cdfc
#include <stdbool.h>
Packit Service 09cdfc
#include <unistd.h>
Packit Service 09cdfc
#include <stdio.h>
Packit Service 09cdfc
#include <stdlib.h>
Packit Service 09cdfc
#include <stddef.h>
Packit Service 09cdfc
#include <errno.h>
Packit Service 09cdfc
#include <limits.h>
Packit Service 09cdfc
#include <ctype.h>
Packit Service 09cdfc
#include <sys/xattr.h>
Packit Service 09cdfc
#include "cifsacl.h"
Packit Service 09cdfc
#include "idmap_plugin.h"
Packit Service 09cdfc
Packit Service 09cdfc
static void *plugin_handle;
Packit Service 09cdfc
static bool plugin_loaded;
Packit Service 016a2b
static char *execname;
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
print_each_ace_mask(uint32_t mask)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if ((mask & ALL_READ_BITS) && ((mask & EREAD) != EREAD &&
Packit Service 09cdfc
			(mask & OREAD) != OREAD && (mask & BREAD) != BREAD)) {
Packit Service 09cdfc
		printf("0x%x", mask);
Packit Service 09cdfc
		return;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if ((mask & ALL_WRITE_BITS) && (mask & EWRITE) != EWRITE) {
Packit Service 09cdfc
		printf("0x%x", mask);
Packit Service 09cdfc
		return;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if ((mask & EREAD) == EREAD || (mask & OREAD) == OREAD ||
Packit Service 09cdfc
			(mask & BREAD) == BREAD)
Packit Service 09cdfc
		printf("R");
Packit Service 09cdfc
	if ((mask & EWRITE) == EWRITE)
Packit Service 09cdfc
		printf("W");
Packit Service 09cdfc
	if ((mask & EXEC) == EXEC)
Packit Service 09cdfc
		printf("X");
Packit Service 09cdfc
	if ((mask & DELETE) == DELETE)
Packit Service 09cdfc
		printf("D");
Packit Service 09cdfc
	if ((mask & WRITE_DAC) == WRITE_DAC)
Packit Service 09cdfc
		printf("P");
Packit Service 09cdfc
	if ((mask & WRITE_OWNER) == WRITE_OWNER)
Packit Service 09cdfc
		printf("O");
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
print_ace_mask(uint32_t mask, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (raw) {
Packit Service 09cdfc
		printf("0x%x\n", mask);
Packit Service 09cdfc
		return;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (mask == FULL_CONTROL)
Packit Service 09cdfc
		printf("FULL");
Packit Service 09cdfc
	else if (mask == CHANGE)
Packit Service 09cdfc
		printf("CHANGE");
Packit Service 09cdfc
	else if (mask == DELETE)
Packit Service 09cdfc
		printf("D");
Packit Service 09cdfc
	else if (mask == EREAD)
Packit Service 09cdfc
		printf("READ");
Packit Service 09cdfc
	else if (mask & DELDHLD)
Packit Service 09cdfc
		printf("0x%x", mask);
Packit Service 09cdfc
	else
Packit Service 09cdfc
		print_each_ace_mask(mask);
Packit Service 09cdfc
Packit Service 09cdfc
	printf("\n");
Packit Service 09cdfc
	return;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
print_ace_flags(uint8_t flags, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	bool mflags = false;
Packit Service 09cdfc
Packit Service 09cdfc
	if (raw) {
Packit Service 09cdfc
		printf("0x%x", flags);
Packit Service 09cdfc
		return;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (flags & OBJECT_INHERIT_FLAG) {
Packit Service 09cdfc
		mflags = true;
Packit Service 09cdfc
		printf("OI");
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (flags & CONTAINER_INHERIT_FLAG) {
Packit Service 09cdfc
		if (mflags)
Packit Service 09cdfc
			printf("|");
Packit Service 09cdfc
		else
Packit Service 09cdfc
			mflags = true;
Packit Service 09cdfc
		printf("CI");
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (flags & NO_PROPAGATE_INHERIT_FLAG) {
Packit Service 09cdfc
		if (mflags)
Packit Service 09cdfc
			printf("|");
Packit Service 09cdfc
		else
Packit Service 09cdfc
			mflags = true;
Packit Service 09cdfc
		printf("NP");
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (flags & INHERIT_ONLY_FLAG) {
Packit Service 09cdfc
		if (mflags)
Packit Service 09cdfc
			printf("|");
Packit Service 09cdfc
		else
Packit Service 09cdfc
			mflags = true;
Packit Service 09cdfc
		printf("IO");
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (flags & INHERITED_ACE_FLAG) {
Packit Service 09cdfc
		if (mflags)
Packit Service 09cdfc
			printf("|");
Packit Service 09cdfc
		else
Packit Service 09cdfc
			mflags = true;
Packit Service 09cdfc
		printf("I");
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (!mflags)
Packit Service 09cdfc
		printf("0x0");
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
print_ace_type(uint8_t acetype, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (raw) {
Packit Service 09cdfc
		printf("0x%x", acetype);
Packit Service 09cdfc
		return;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	switch (acetype) {
Packit Service 09cdfc
	case ACCESS_ALLOWED:
Packit Service 09cdfc
		printf("ALLOWED");
Packit Service 09cdfc
		break;
Packit Service 09cdfc
	case ACCESS_DENIED:
Packit Service 09cdfc
		printf("DENIED");
Packit Service 09cdfc
		break;
Packit Service 09cdfc
	case ACCESS_ALLOWED_OBJECT:
Packit Service 09cdfc
		printf("OBJECT_ALLOWED");
Packit Service 09cdfc
		break;
Packit Service 09cdfc
	case ACCESS_DENIED_OBJECT:
Packit Service 09cdfc
		printf("OBJECT_DENIED");
Packit Service 09cdfc
		break;
Packit Service 09cdfc
	default:
Packit Service 09cdfc
		printf("UNKNOWN");
Packit Service 09cdfc
		break;
Packit Service 09cdfc
	}
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
print_sid(struct cifs_sid *csid, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int i, rc;
Packit Service 09cdfc
	char *name;
Packit Service 09cdfc
	unsigned long long id_auth_val;
Packit Service 09cdfc
Packit Service 09cdfc
	if (raw || !plugin_loaded)
Packit Service 09cdfc
		goto print_sid_raw;
Packit Service 09cdfc
Packit Service 09cdfc
	rc = sid_to_str(plugin_handle, csid, &name);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		goto print_sid_raw;
Packit Service 09cdfc
Packit Service 09cdfc
	printf("%s", name);
Packit Service 09cdfc
	free(name);
Packit Service 09cdfc
	return;
Packit Service 09cdfc
Packit Service 09cdfc
print_sid_raw:
Packit Service 09cdfc
	printf("S-%hhu", csid->revision);
Packit Service 09cdfc
Packit Service 09cdfc
	id_auth_val = (unsigned long long)csid->authority[5];
Packit Service 09cdfc
	id_auth_val += (unsigned long long)csid->authority[4] << 8;
Packit Service 09cdfc
	id_auth_val += (unsigned long long)csid->authority[3] << 16;
Packit Service 09cdfc
	id_auth_val += (unsigned long long)csid->authority[2] << 24;
Packit Service 09cdfc
	id_auth_val += (unsigned long long)csid->authority[1] << 32;
Packit Service 09cdfc
	id_auth_val += (unsigned long long)csid->authority[0] << 40;
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * MS-DTYP states that if the authority is >= 2^32, then it should be
Packit Service 09cdfc
	 * expressed as a hex value.
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	if (id_auth_val <= UINT_MAX)
Packit Service 09cdfc
		printf("-%llu", id_auth_val);
Packit Service 09cdfc
	else
Packit Service 09cdfc
		printf("-0x%llx", id_auth_val);
Packit Service 09cdfc
Packit Service 09cdfc
	for (i = 0; i < csid->num_subauth; i++)
Packit Service 09cdfc
		printf("-%u", le32toh(csid->sub_auth[i]));
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
print_ace(struct cifs_ace *pace, char *end_of_acl, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	uint16_t size;
Packit Service 09cdfc
Packit Service 09cdfc
	/* make sure we can safely get to "size" */
Packit Service 09cdfc
	if (end_of_acl < (char *)pace + offsetof(struct cifs_ace, size) + 1)
Packit Service 09cdfc
		return;
Packit Service 09cdfc
Packit Service 09cdfc
	size = le16toh(pace->size);
Packit Service 09cdfc
Packit Service 09cdfc
	/* 16 == size of cifs_ace when cifs_sid has no subauths */
Packit Service 09cdfc
	if (size < 16)
Packit Service 09cdfc
		return;
Packit Service 09cdfc
Packit Service 09cdfc
	/* validate that we do not go past end of acl */
Packit Service 09cdfc
	if (end_of_acl < (char *)pace + size)
Packit Service 09cdfc
		return;
Packit Service 09cdfc
Packit Service 09cdfc
	printf("ACL:");
Packit Service 09cdfc
	print_sid((struct cifs_sid *)&pace->sid, raw);
Packit Service 09cdfc
	printf(":");
Packit Service 09cdfc
	print_ace_type(pace->type, raw);
Packit Service 09cdfc
	printf("/");
Packit Service 09cdfc
	print_ace_flags(pace->flags, raw);
Packit Service 09cdfc
	printf("/");
Packit Service 09cdfc
	print_ace_mask(le32toh(pace->access_req), raw);
Packit Service 09cdfc
Packit Service 09cdfc
	return;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int i;
Packit Service 09cdfc
	int num_aces = 0;
Packit Service 09cdfc
	int acl_size;
Packit Service 09cdfc
	char *acl_base;
Packit Service 09cdfc
	struct cifs_ace *pace;
Packit Service 09cdfc
Packit Service 09cdfc
	if (!pdacl)
Packit Service 09cdfc
		return;
Packit Service 09cdfc
Packit Service 09cdfc
	if (end_of_acl < (char *)pdacl + le16toh(pdacl->size))
Packit Service 09cdfc
		return;
Packit Service 09cdfc
Packit Service 09cdfc
	acl_base = (char *)pdacl;
Packit Service 09cdfc
	acl_size = sizeof(struct cifs_ctrl_acl);
Packit Service 09cdfc
Packit Service 09cdfc
	num_aces = le32toh(pdacl->num_aces);
Packit Service 09cdfc
	if (num_aces  > 0) {
Packit Service 09cdfc
		for (i = 0; i < num_aces; ++i) {
Packit Service 09cdfc
			pace = (struct cifs_ace *) (acl_base + acl_size);
Packit Service 09cdfc
			print_ace(pace, end_of_acl, raw);
Packit Service 09cdfc
			acl_base = (char *)pace;
Packit Service 09cdfc
			acl_size = le16toh(pace->size);
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	return;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
parse_sid(struct cifs_sid *psid, char *end_of_acl, char *title, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (end_of_acl < (char *)psid + 8)
Packit Service 09cdfc
		return -EINVAL;
Packit Service 09cdfc
Packit Service 09cdfc
	if (title)
Packit Service 09cdfc
		printf("%s:", title);
Packit Service 09cdfc
	print_sid((struct cifs_sid *)psid, raw);
Packit Service 09cdfc
	printf("\n");
Packit Service 09cdfc
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc;
Packit Service 09cdfc
	uint32_t dacloffset;
Packit Service 09cdfc
	char *end_of_acl = ((char *)pntsd) + acl_len;
Packit Service 09cdfc
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Packit Service 09cdfc
	struct cifs_ctrl_acl *dacl_ptr; /* no need for SACL ptr */
Packit Service 09cdfc
Packit Service 09cdfc
	if (pntsd == NULL)
Packit Service 09cdfc
		return -EIO;
Packit Service 09cdfc
Packit Service 09cdfc
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Packit Service 09cdfc
				le32toh(pntsd->osidoffset));
Packit Service 09cdfc
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Packit Service 09cdfc
				le32toh(pntsd->gsidoffset));
Packit Service 09cdfc
	dacloffset = le32toh(pntsd->dacloffset);
Packit Service 09cdfc
	dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
Packit Service 09cdfc
	printf("REVISION:0x%x\n", le16toh(pntsd->revision));
Packit Service 09cdfc
	printf("CONTROL:0x%x\n", le16toh(pntsd->type));
Packit Service 09cdfc
Packit Service 09cdfc
	rc = parse_sid(owner_sid_ptr, end_of_acl, "OWNER", raw);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return rc;
Packit Service 09cdfc
Packit Service 09cdfc
	rc = parse_sid(group_sid_ptr, end_of_acl, "GROUP", raw);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return rc;
Packit Service 09cdfc
Packit Service 09cdfc
	if (dacloffset)
Packit Service 09cdfc
		parse_dacl(dacl_ptr, end_of_acl, raw);
Packit Service 09cdfc
	else
Packit Service 09cdfc
		printf("No ACL\n"); /* BB grant all or default perms? */
Packit Service 09cdfc
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void
Packit Service 09cdfc
getcifsacl_usage(const char *prog)
Packit Service 09cdfc
{
Packit Service 09cdfc
	fprintf(stderr,
Packit Service 09cdfc
	"%s: Display CIFS/NTFS ACL in a security descriptor of a file object\n",
Packit Service 09cdfc
		prog);
Packit Service 09cdfc
	fprintf(stderr, "Usage: %s [option] <file_name>\n", prog);
Packit Service 09cdfc
	fprintf(stderr, "Valid options:\n");
Packit Service 016a2b
	fprintf(stderr, "\t-h	Display this help text\n");
Packit Service 016a2b
	fprintf(stderr, "\n");
Packit Service 09cdfc
	fprintf(stderr, "\t-v	Version of the program\n");
Packit Service 09cdfc
	fprintf(stderr, "\n");
Packit Service 09cdfc
	fprintf(stderr, "\t-r	Display raw values of the ACE fields\n");
Packit Service 09cdfc
	fprintf(stderr, "\nRefer to getcifsacl(1) manpage for details\n");
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
int
Packit Service 09cdfc
main(const int argc, char *const argv[])
Packit Service 09cdfc
{
Packit Service 09cdfc
	int c, ret = 0;
Packit Service 09cdfc
	bool raw = false;
Packit Service 09cdfc
	ssize_t attrlen;
Packit Service 09cdfc
	size_t bufsize = BUFSIZE;
Packit Service 09cdfc
	char *filename, *attrval;
Packit Service 016a2b
	execname = basename(argv[0]);
Packit Service 016a2b
Packit Service 016a2b
	if (argc < 2) {
Packit Service 016a2b
		fprintf(stderr, "%s: you must specify a filename.\n", execname);
Packit Service 016a2b
		printf("Try `getcifsacl -h' for more information.\n");
Packit Service 016a2b
		goto out;
Packit Service 016a2b
	}
Packit Service 09cdfc
Packit Service 016a2b
	while ((c = getopt_long(argc, argv, "rhv", NULL, NULL)) != -1) {
Packit Service 09cdfc
		switch (c) {
Packit Service 09cdfc
		case 'v':
Packit Service 09cdfc
			printf("Version: %s\n", VERSION);
Packit Service 09cdfc
			goto out;
Packit Service 09cdfc
		case 'r':
Packit Service 09cdfc
			raw = true;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		default:
Packit Service 016a2b
			getcifsacl_usage(execname);
Packit Service 016a2b
			goto out;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 016a2b
	if (optind >= argc) {
Packit Service 016a2b
		printf("you must specify a filename after options.\n");
Packit Service 016a2b
		printf("Usage: getcifsacl [option] <file_name>\n");
Packit Service 09cdfc
		goto out;
Packit Service 016a2b
	} else
Packit Service 016a2b
		filename = argv[optind];
Packit Service 09cdfc
Packit Service 09cdfc
	if (!raw && !plugin_loaded) {
Packit Service 09cdfc
		ret = init_plugin(&plugin_handle);
Packit Service 09cdfc
		if (ret)
Packit Service 09cdfc
			printf("WARNING: unable to initialize idmapping plugin: %s\n",
Packit Service 09cdfc
				plugin_errmsg);
Packit Service 09cdfc
		else
Packit Service 09cdfc
			plugin_loaded = true;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
cifsacl:
Packit Service 09cdfc
	if (bufsize >= XATTR_SIZE_MAX) {
Packit Service 09cdfc
		printf("buffer to allocate exceeds max size of %d\n",
Packit Service 09cdfc
				XATTR_SIZE_MAX);
Packit Service 09cdfc
		ret = -1;
Packit Service 09cdfc
		goto out;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	attrval = malloc(bufsize * sizeof(char));
Packit Service 09cdfc
	if (!attrval) {
Packit Service 09cdfc
		printf("error allocating memory for attribute value buffer\n");
Packit Service 09cdfc
		ret = -1;
Packit Service 09cdfc
		goto out;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
Packit Service 09cdfc
	if (attrlen == -1) {
Packit Service 09cdfc
		if (errno == ERANGE) {
Packit Service 09cdfc
			free(attrval);
Packit Service 09cdfc
			bufsize += BUFSIZE;
Packit Service 09cdfc
			goto cifsacl;
Packit Service 7e6443
		} else {
Packit Service 7e6443
			fprintf(stderr, "getxattr failed on %s: %s\n", filename, strerror(errno) );
Packit Service 7e6443
			free(attrval);
Packit Service 7e6443
			ret = -1;
Packit Service 7e6443
			goto out;
Packit Service 7e6443
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	parse_sec_desc((struct cifs_ntsd *)attrval, attrlen, raw);
Packit Service 09cdfc
Packit Service 09cdfc
	free(attrval);
Packit Service 09cdfc
out:
Packit Service 09cdfc
	if (plugin_loaded)
Packit Service 09cdfc
		exit_plugin(plugin_handle);
Packit Service 09cdfc
	return ret;
Packit Service 09cdfc
}