From: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> Parse the blob that contains a security descriptor obtained by calling getxattr API using attribute system.cifs_acl . Start parsing and printing security descriptor including the a DACL within the security descriptor, printing each ACE of the DACL by printing SID, type, flags, and mask. Winbind apis are used to translate raw SID to a name. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> --- getcifsacl.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 389 insertions(+), 0 deletions(-) create mode 100644 getcifsacl.c diff --git a/getcifsacl.c b/getcifsacl.c new file mode 100644 index 0000000..19b1fec --- /dev/null +++ b/getcifsacl.c @@ -0,0 +1,389 @@ +/* +* getcifsacl utility +* +* Copyright (C) Shirish Pargaonkar (shirishp@xxxxxxxxxx) 2011 +* +* Used to display a security descriptor including ACL of a file object +* that belongs to a share mounted using option cifsacl. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <getopt.h> +#include <syslog.h> +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <wbclient.h> +#include <ctype.h> +#include <sys/xattr.h> +#include "cifsacl.h" + +static const char *prog = "getcifsacl"; + +static void +print_each_ace_mask(uint32_t mask) +{ + if ((mask & ALL_READ_BITS) && ((mask & EREAD) != EREAD && + (mask & OREAD) != OREAD && (mask & BREAD) != BREAD)) { + printf("0x%x", mask); + return; + } + + if ((mask & ALL_WRITE_BITS) && (mask & EWRITE) != EWRITE) { + printf("0x%x", mask); + return; + } + + if ((mask & EREAD) == EREAD || (mask & OREAD) == OREAD || + (mask & BREAD) == BREAD) + printf("R"); + if ((mask & EWRITE) == EWRITE) + printf("W"); + if ((mask & EXEC) == EXEC) + printf("X"); + if ((mask & DELETE) == DELETE) + printf("D"); + if ((mask & WRITE_DAC) == WRITE_DAC) + printf("P"); + if ((mask & WRITE_OWNER) == WRITE_OWNER) + printf("O"); +} + +static void +print_ace_mask(uint32_t mask, int raw) +{ + if (raw) { + printf("0x%x\n", mask); + return; + } + + if (mask == FULL_CONTROL) + printf("FULL"); + else if (mask == CHANGE) + printf("CHANGE"); + else if (mask == DELETE) + printf("D"); + else if (mask == EREAD) + printf("READ"); + else if (mask & DELDHLD) + printf("0x%x", mask); + else + print_each_ace_mask(mask); + + printf("\n"); + return; +} + +static void +print_ace_flags(uint8_t flags, int raw) +{ + bool mflags = false; + + if (raw) { + printf("0x%x", flags); + return; + } + + if (flags & OBJECT_INHERIT_FLAG) { + if (mflags) + printf("|"); + else + mflags = true; + printf("OI"); + } + if (flags & CONTAINER_INHERIT_FLAG) { + if (mflags) + printf("|"); + else + mflags = true; + printf("CI"); + } + if (flags & NO_PROPAGATE_INHERIT_FLAG) { + if (mflags) + printf("|"); + else + mflags = true; + printf("NP"); + } + if (flags & INHERIT_ONLY_FLAG) { + if (mflags) + printf("|"); + else + mflags = true; + printf("IO"); + } + if (flags & INHERITED_ACE_FLAG) { + if (mflags) + printf("|"); + else + mflags = true; + printf("I"); + } + + if (!mflags) + printf("0x0"); +} + +static void +print_ace_type(uint8_t acetype, int raw) +{ + if (raw) { + printf("0x%x", acetype); + return; + } + + switch (acetype) { + case ACCESS_ALLOWED: + printf("ALLOWED"); + break; + case ACCESS_DENIED: + printf("DENIED"); + break; + case ACCESS_ALLOWED_OBJECT: + printf("OBJECT_ALLOWED"); + break; + case ACCESS_DENIED_OBJECT: + printf("OBJECT_DENIED"); + break; + default: + printf("UNKNOWN"); + break; + } +} + +static void +print_sid(struct wbcDomainSid *sidptr, int raw) +{ + int i; + int num_auths; + int num_auth = MAX_NUM_AUTHS; + wbcErr rc; + char *domain_name = NULL; + char *sidname = NULL; + enum wbcSidType sntype; + + if (raw) + goto print_sid_raw; + + rc = wbcLookupSid(sidptr, &domain_name, &sidname, &sntype); + if (!rc) { + printf("%s", domain_name); + if (strlen(domain_name)) + printf("%c", '\\'); + printf("%s", sidname); + return; + } + +print_sid_raw: + num_auths = sidptr->num_auths; + printf("S"); + printf("-%d", sidptr->sid_rev_num); + for (i = 0; i < num_auth; ++i) + if (sidptr->id_auth[i]) + printf("-%d", sidptr->id_auth[i]); + for (i = 0; i < num_auths; i++) + printf("-%u", le32toh(sidptr->sub_auths[i])); +} + +static void +print_ace(struct cifs_ace *pace, char *end_of_acl, int raw) +{ + /* validate that we do not go past end of acl */ + + if (le16toh(pace->size) < 16) + return; + + if (end_of_acl < (char *)pace + le16toh(pace->size)) + return; + + printf("ACL:"); + print_sid((struct wbcDomainSid *)&pace->sid, raw); + printf(":"); + print_ace_type(pace->type, raw); + printf("/"); + print_ace_flags(pace->flags, raw); + printf("/"); + print_ace_mask(pace->access_req, raw); + + + return; +} + +static void +parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw) +{ + int i; + int num_aces = 0; + int acl_size; + char *acl_base; + struct cifs_ace *pace; + + if (!pdacl) + return; + + if (end_of_acl < (char *)pdacl + le16toh(pdacl->size)) + return; + + acl_base = (char *)pdacl; + acl_size = sizeof(struct cifs_ctrl_acl); + + num_aces = le32toh(pdacl->num_aces); + if (num_aces > 0) { + for (i = 0; i < num_aces; ++i) { + pace = (struct cifs_ace *) (acl_base + acl_size); + print_ace(pace, end_of_acl, raw); + acl_base = (char *)pace; + acl_size = le16toh(pace->size); + } + } + + return; +} + +static int +parse_sid(struct wbcDomainSid *psid, char *end_of_acl, char *title, int raw) +{ + if (end_of_acl < (char *)psid + 8) + return -EINVAL; + + if (title) + printf("%s:", title); + print_sid((struct wbcDomainSid *)psid, raw); + printf("\n"); + + return 0; +} + +static int +parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw) +{ + int rc; + uint32_t dacloffset; + char *end_of_acl = ((char *)pntsd) + acl_len; + struct wbcDomainSid *owner_sid_ptr, *group_sid_ptr; + struct cifs_ctrl_acl *dacl_ptr; /* no need for SACL ptr */ + + if (pntsd == NULL) + return -EIO; + + owner_sid_ptr = (struct wbcDomainSid *)((char *)pntsd + + le32toh(pntsd->osidoffset)); + group_sid_ptr = (struct wbcDomainSid *)((char *)pntsd + + le32toh(pntsd->gsidoffset)); + dacloffset = le32toh(pntsd->dacloffset); + dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset); + printf("REVISION:0x%x\n", pntsd->revision); + printf("CONTROL:0x%x\n", pntsd->type); + + rc = parse_sid(owner_sid_ptr, end_of_acl, "OWNER", raw); + if (rc) + return rc; + + rc = parse_sid(group_sid_ptr, end_of_acl, "GROUP", raw); + if (rc) + return rc; + + if (dacloffset) + parse_dacl(dacl_ptr, end_of_acl, raw); + else + printf("No ACL\n"); /* BB grant all or default perms? */ + + return 0; +} + +static void +getcifsacl_usage(void) +{ + fprintf(stderr, + "%s: Display CIFS/NTFS ACL in a security descriptor of a file object\n", + prog); + fprintf(stderr, "Usage: %s [option] <file_name>\n", prog); + fprintf(stderr, "Valid options:\n"); + fprintf(stderr, "\t-v Version of the program\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "\t-r Display raw values of the ACE fields\n"); + fprintf(stderr, "\nRefer to getcifsacl(8) manpage for details\n"); +} + +int +main(const int argc, char *const argv[]) +{ + int c, raw = 0; + ssize_t attrlen; + size_t bufsize = BUFSIZE; + char *filename, *attrval; + + openlog(prog, 0, LOG_DAEMON); + + while ((c = getopt_long(argc, argv, "r:v", NULL, NULL)) != -1) { + switch (c) { + case 'v': + printf("Version: %s\n", VERSION); + goto out; + case 'r': + raw = 1; + break; + default: + break; + } + } + + if (raw && argc == 3) + filename = argv[2]; + else if (argc == 2) + filename = argv[1]; + else { + getcifsacl_usage(); + return 0; + } + +cifsacl: + if (bufsize >= XATTR_SIZE_MAX) { + printf("buffer to allocate exceeds max size of %d\n", + XATTR_SIZE_MAX); + return -1; + } + + attrval = malloc(bufsize * sizeof(char)); + if (!attrval) { + printf("error allocating memory for attribute value buffer\n"); + return -1; + } + + attrlen = getxattr(filename, ATTRNAME, attrval, bufsize); + if (attrlen == -1) { + if (errno == ERANGE) { + free(attrval); + bufsize += BUFSIZE; + goto cifsacl; + } else + printf("getxattr error: %d\n", errno); + } + + parse_sec_desc((struct cifs_ntsd *)attrval, attrlen, raw); + + free(attrval); + +out: + return 0; +} -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html