From patchwork Sat Aug 20 03:27:30 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shirish Pargaonkar X-Patchwork-Id: 1082242 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p7K3LdTo023075 for ; Sat, 20 Aug 2011 03:21:55 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754846Ab1HTDVy (ORCPT ); Fri, 19 Aug 2011 23:21:54 -0400 Received: from mail-gy0-f174.google.com ([209.85.160.174]:47651 "EHLO mail-gy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754635Ab1HTDVy (ORCPT ); Fri, 19 Aug 2011 23:21:54 -0400 Received: by gya6 with SMTP id 6so2619161gya.19 for ; Fri, 19 Aug 2011 20:21:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; bh=dFK25jd910vkdGEIEcsUNLFVGTHVWP/fEVQq4TdSg78=; b=JQel0wMSbo8crwiBTf5UWT5GaT40ehaTOkdSBE0J1IexVJR6RTyfFmlnaW54QFquz7 /lnOzJSzSQ5LkuQ0Nq7c6YBgZ9PySeus0YSGbE0IBS4sj5KBSS16phu4bxVcbeGRVmmE 6idpaSleLcrwgC9mP82yRGNsCgOwQFxWpT52w= Received: by 10.150.150.42 with SMTP id x42mr114024ybd.93.1313810513402; Fri, 19 Aug 2011 20:21:53 -0700 (PDT) Received: from localhost ([32.97.110.58]) by mx.google.com with ESMTPS id k17sm725069yba.29.2011.08.19.20.21.52 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 19 Aug 2011 20:21:52 -0700 (PDT) From: shirishpargaonkar@gmail.com To: jlayton@samba.org Cc: linux-cifs@vger.kernel.org, Shirish Pargaonkar Subject: [PATCH 2/5] cifs-utils: cifsacl utilities: Create file getcifsacl.c Date: Fri, 19 Aug 2011 22:27:30 -0500 Message-Id: <1313810850-2291-1-git-send-email-shirishpargaonkar@gmail.com> X-Mailer: git-send-email 1.6.0.2 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Sat, 20 Aug 2011 03:21:55 +0000 (UTC) From: Shirish Pargaonkar 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 --- getcifsacl.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 372 insertions(+), 0 deletions(-) create mode 100644 getcifsacl.c diff --git a/getcifsacl.c b/getcifsacl.c new file mode 100644 index 0000000..e11148f --- /dev/null +++ b/getcifsacl.c @@ -0,0 +1,372 @@ +/* +* getcifsacl utility +* +* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 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 +*/ + +#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] \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; +}