From: Shirish Pargaonkar <[email protected]>

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 <[email protected]>
---
 setcifsacl.c |  905 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 905 insertions(+), 0 deletions(-)
 create mode 100644 setcifsacl.c

diff --git a/setcifsacl.c b/setcifsacl.c
new file mode 100644
index 0000000..0f283cd
--- /dev/null
+++ b/setcifsacl.c
@@ -0,0 +1,905 @@
+/*
+* setcifsacl utility
+*
+* Copyright (C) Shirish Pargaonkar ([email protected]) 2011
+*
+* Used to alter entries of an ACL or replace an entire ACL in a
+* security descriptor of a file system 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 = "setcifsacl";
+
+static void
+copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
+               int numaces, int acessize)
+{
+       int i;
+
+       int osidsoffset, gsidsoffset, dacloffset;
+       struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
+       struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
+       struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
+
+       /* copy security descriptor control portion */
+       osidsoffset = htole32(pntsd->osidoffset);
+       gsidsoffset = htole32(pntsd->gsidoffset);
+       dacloffset = htole32(pntsd->dacloffset);
+
+       pnntsd->revision = pntsd->revision;
+       pnntsd->type = pntsd->type;
+       pnntsd->osidoffset = pntsd->osidoffset;
+       pnntsd->gsidoffset = pntsd->gsidoffset;
+       pnntsd->dacloffset = pntsd->dacloffset;
+
+       dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+       ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
+
+       ndacl_ptr->revision = dacl_ptr->revision;
+       ndacl_ptr->size = htole16(acessize + sizeof(struct cifs_ctrl_acl));
+       ndacl_ptr->num_aces = htole32(numaces);
+
+       /* copy owner sid */
+       owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
+       nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
+
+       nowner_sid_ptr->revision = owner_sid_ptr->revision;
+       nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
+       for (i = 0; i < 6; i++)
+               nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
+       for (i = 0; i < 5; i++)
+               nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
+
+       /* copy group sid */
+       group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
+       ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
+
+       ngroup_sid_ptr->revision = group_sid_ptr->revision;
+       ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
+       for (i = 0; i < 6; i++)
+               ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
+       for (i = 0; i < 5; i++)
+               ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
+
+       return;
+}
+
+static int
+copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
+{
+       int i;
+
+       dace->type = sace->type;
+       dace->flags = sace->flags;
+       dace->access_req = htole32(sace->access_req);
+
+       dace->sid.revision = sace->sid.revision;
+       dace->sid.num_subauth = sace->sid.num_subauth;
+       for (i = 0; i < 6; i++)
+               dace->sid.authority[i] = sace->sid.authority[i];
+       for (i = 0; i < sace->sid.num_subauth; i++)
+               dace->sid.sub_auth[i] = sace->sid.sub_auth[i];
+
+       dace->size = htole16(sace->size);
+
+       return dace->size;
+}
+
+static int
+compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
+{
+       int i;
+
+       if (compflags & COMPSID) {
+               if (dace->sid.revision != sace->sid.revision)
+                       return 0;
+               if (dace->sid.num_subauth != sace->sid.num_subauth)
+                       return 0;
+               for (i = 0; i < 6; i++) {
+                       if (dace->sid.authority[i] != sace->sid.authority[i])
+                               return 0;
+               }
+               for (i = 0; i < sace->sid.num_subauth; i++) {
+                       if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
+                               return 0;
+               }
+       }
+
+       if (compflags & COMPTYPE) {
+               if (dace->type != sace->type)
+                       return 0;
+       }
+
+       if (compflags & COMPFLAG) {
+               if (dace->flags != sace->flags)
+                       return 0;
+       }
+
+       if (compflags & COMPMASK) {
+               if (dace->access_req != htole32(sace->access_req))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int
+get_sec_desc_size(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
+                       int aces, ssize_t *bufsize, size_t *acesoffset)
+{
+       unsigned int size, acessize, dacloffset;
+
+       size = sizeof(struct cifs_ntsd) +
+               2 * sizeof(struct cifs_sid) +
+               sizeof(struct cifs_ctrl_acl);
+
+       dacloffset = le32toh(pntsd->dacloffset);
+
+       *acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
+       acessize = aces * sizeof(struct cifs_ace);
+       *bufsize = size + acessize;
+
+       *npntsd = malloc(*bufsize);
+       if (!*npntsd) {
+               printf("%s: Memory allocation failure", __func__);
+               return errno;
+       }
+
+       return 0;
+}
+
+static int
+ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
+                       struct cifs_ace **cacesptr, int numcaces)
+{
+       int i, rc, acessize = 0;
+       size_t acesoffset;
+       char *acesptr;
+
+       rc = get_sec_desc_size(pntsd, npntsd, numcaces, bufsize, &acesoffset);
+       if (rc)
+               return rc;
+
+       acesptr = (char *)*npntsd + acesoffset;
+       for (i = 0; i < numcaces; ++i) {
+               acessize += copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
+               acesptr += sizeof(struct cifs_ace);
+       }
+       copy_sec_desc(pntsd, *npntsd, numcaces, acessize);
+       acesptr = (char *)*npntsd + acesoffset;
+
+
+       return 0;
+}
+
+static int
+ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
+               struct cifs_ace **facesptr, int numfaces,
+               struct cifs_ace **cacesptr, int numcaces)
+{
+       int i, rc, numaces, size, acessize = 0;
+       size_t acesoffset;
+       char *acesptr;
+
+       numaces = numfaces + numcaces;
+       rc = get_sec_desc_size(pntsd, npntsd, numaces, bufsize, &acesoffset);
+       if (rc)
+               return rc;
+
+       acesptr = (char *)*npntsd + acesoffset;
+       for (i = 0; i < numfaces; ++i) {
+               size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
+               acesptr += size;
+               acessize += size;
+       }
+       for (i = 0; i < numcaces; ++i) {
+               size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
+               acesptr += size;
+               acessize += size;
+       }
+       copy_sec_desc(pntsd, *npntsd, numaces, acessize);
+
+       return 0;
+}
+
+static int
+ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t 
*bufsize,
+               struct cifs_ace **facesptr, int numfaces,
+               struct cifs_ace **cacesptr, int numcaces)
+{
+       int i, j, rc, size, acessize = 0;
+       size_t acesoffset;
+       char *acesptr;
+
+       if (numfaces == 0) {
+               printf("%s: No entries to modify", __func__);
+               return -1;
+       }
+
+       rc = get_sec_desc_size(pntsd, npntsd, numfaces, bufsize, &acesoffset);
+       if (rc)
+               return rc;
+
+       for (j = 0; j < numcaces; ++j) {
+               for (i = 0; i < numfaces; ++i) {
+                       if (compare_aces(facesptr[i], cacesptr[j],
+                                       COMPSID | COMPTYPE)) {
+                               copy_ace(facesptr[i], cacesptr[j]);
+                               break;
+                       }
+               }
+       }
+
+       acesptr = (char *)*npntsd + acesoffset;
+       for (i = 0; i < numfaces; ++i) {
+               size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
+               acesptr += size;
+               acessize += size;
+       }
+
+       copy_sec_desc(pntsd, *npntsd, numfaces, acessize);
+
+       return 0;
+}
+
+static int
+ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t 
*bufsize,
+               struct cifs_ace **facesptr, int numfaces,
+               struct cifs_ace **cacesptr, int numcaces)
+{
+       int i, j, numaces = 0, rc, size, acessize = 0;
+       size_t acesoffset;
+       char *acesptr;
+
+       if (numfaces == 0) {
+               printf("%s: No entries to delete\n", __func__);
+               return -1;
+       }
+
+       if (numfaces < numcaces) {
+               printf("%s: Invalid entries to delete\n", __func__);
+               return -1;
+       }
+
+       rc = get_sec_desc_size(pntsd, npntsd, numfaces, bufsize, &acesoffset);
+       if (rc)
+               return rc;
+
+       acesptr = (char *)*npntsd + acesoffset;
+       for (i = 0; i < numfaces; ++i) {
+               for (j = 0; j < numcaces; ++j) {
+                       if (compare_aces(facesptr[i], cacesptr[j], COMPALL))
+                               break;
+               }
+               if (j == numcaces) {
+                       size = copy_ace((struct cifs_ace *)acesptr,
+                                                               facesptr[i]);
+                       acessize += size;
+                       acesptr += size;
+                       ++numaces;
+               }
+       }
+
+       if (numaces == numfaces) {
+               printf("%s: Nothing to delete\n", __func__);
+               return 1;
+       }
+       copy_sec_desc(pntsd, *npntsd, numaces, acessize);
+
+       return 0;
+}
+
+static int
+get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
+                       struct cifs_ctrl_acl **daclptr)
+{
+       int numfaces = 0;
+       uint32_t dacloffset;
+       struct cifs_ctrl_acl *ldaclptr;
+       char *end_of_acl = ((char *)pntsd) + acl_len;
+
+       if (pntsd == NULL)
+               return 0;
+
+       dacloffset = le32toh(pntsd->dacloffset);
+       if (!dacloffset)
+               return 0;
+       else {
+               ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+               /* validate that we do not go past end of acl */
+               if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
+                       numfaces = le32toh(ldaclptr->num_aces);
+                       *daclptr = ldaclptr;
+               }
+       }
+
+       return numfaces;
+}
+
+static struct cifs_ace **
+build_fetched_aces(char *daclptr, int numfaces)
+{
+       int i, j, rc = 0, acl_size;
+       char *acl_base;
+       struct cifs_ace *pace, **facesptr;
+
+       facesptr = (struct cifs_ace **)malloc(numfaces *
+                                       sizeof(struct cifs_aces *));
+       if (!facesptr) {
+               printf("%s: Error %d allocating ACE array",
+                               __func__, errno);
+               rc = errno;
+       }
+
+       acl_base = daclptr;
+       acl_size = sizeof(struct cifs_ctrl_acl);
+       for (i = 0; i < numfaces; ++i) {
+               facesptr[i] = malloc(sizeof(struct cifs_ace));
+               if (!facesptr[i]) {
+                       rc = errno;
+                       goto build_fetched_aces_ret;
+               }
+               pace = (struct cifs_ace *) (acl_base + acl_size);
+               memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
+               acl_base = (char *)pace;
+               acl_size = le16toh(pace->size);
+       }
+
+build_fetched_aces_ret:
+       if (rc) {
+               printf("%s: Invalid fetched ace\n", __func__);
+               if (i) {
+                       for (j = i; j >= 0; --j)
+                               free(facesptr[j]);
+               }
+               free(facesptr);
+       }
+       return facesptr;
+}
+
+static int
+verify_ace_sid(char *sidstr, struct cifs_sid *sid)
+{
+       int rc;
+       char *lstr;
+       struct passwd *winpswdptr;
+
+       lstr = strstr(sidstr, "\\"); /* everything before | */
+       if (lstr)
+               ++lstr;
+       else
+               lstr = sidstr;
+
+       /* Check if it is a (raw) SID (string) */
+       rc = wbcStringToSid(lstr, (struct wbcDomainSid *)sid);
+       if (!rc)
+               return rc;
+
+       /* Check if it a name (string) which can be resolved to a SID*/
+       rc = wbcGetpwnam(lstr, &winpswdptr);
+       if (rc) {
+               printf("%s: Invalid user name: %s\n", __func__, sidstr);
+               return rc;
+       }
+       rc = wbcUidToSid(winpswdptr->pw_uid, (struct wbcDomainSid *)sid);
+       if (rc) {
+               printf("%s: Invalid user: %s\n", __func__, sidstr);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int
+verify_ace_type(char *typestr, uint8_t *typeval)
+{
+       int i, len;
+       char *invaltype;
+
+       if (strstr(typestr, "0x")) { /* hex type value */
+               *typeval = strtol(typestr, &invaltype, 16);
+               if (!strlen(invaltype)) {
+                       if (*typeval != ACCESS_ALLOWED &&
+                               *typeval != ACCESS_DENIED &&
+                               *typeval != ACCESS_ALLOWED_OBJECT &&
+                               *typeval != ACCESS_DENIED_OBJECT) {
+                                       printf("%s: Invalid type: %s\n",
+                                               __func__, typestr);
+                                       return 1;
+                       }
+                       return 0;
+               }
+       }
+
+       len = strlen(typestr);
+       for (i = 0; i < len; ++i)
+               *(typestr + i) = toupper(*(typestr + i));
+       if (!strcmp(typestr, "ALLOWED"))
+               *typeval = 0x0;
+       else if (!strcmp(typestr, "DENIED"))
+               *typeval = 0x1;
+       else if (!strcmp(typestr, "ALLOWED_OBJECT"))
+               *typeval = 0x5;
+       else if (!strcmp(typestr, "DENIED_OBJECT"))
+               *typeval = 0x6;
+       else {
+               printf("%s: Invalid type: %s\n", __func__, typestr);
+               return 1;
+       }
+
+       return 0;
+}
+
+static uint8_t
+ace_flag_value(char *flagstr)
+{
+       uint8_t flagval = 0x0;
+       char *iflag;
+
+       iflag = strtok(flagstr, "|"); /* everything before | */
+       while (iflag) {
+               if (!strcmp(iflag, "OI"))
+                       flagval += 0x1;
+               else if (!strcmp(iflag, "CI"))
+                       flagval += 0x2;
+               else if (!strcmp(iflag, "NP"))
+                       flagval += 0x4;
+               else if (!strcmp(iflag, "IO"))
+                       flagval += 0x8;
+               else if (!strcmp(iflag, "I"))
+                       flagval += 0x10;
+               else
+                       return 0x0; /* Invalid flag */
+               iflag = strtok(NULL, "|"); /* everything before | */
+       }
+
+       return flagval;
+}
+
+static int
+verify_ace_flags(char *flagstr, uint8_t *flagval)
+{
+       char *invalflag;
+
+       if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
+               return 0;
+
+       if (strstr(flagstr, "0x")) { /* hex flag value */
+               *flagval = strtol(flagstr, &invalflag, 16);
+               if (strlen(invalflag)) {
+                       printf("%s: Invalid flags: %s\n", __func__, flagstr);
+                       return 1;
+               }
+       } else
+               *flagval = ace_flag_value(flagstr);
+
+       if (!*flagval || (*flagval & ~VFLAGS)) {
+               printf("%s: Invalid flag %s and value: 0x%x\n",
+                       __func__, flagstr, *flagval);
+               return 1;
+       }
+
+       return 0;
+}
+
+static uint32_t
+ace_mask_value(char *maskstr)
+{
+       int i, len;
+       uint32_t maskval = 0x0;
+       char *lmask;
+
+       if (!strcmp(maskstr, "FULL"))
+               return FULL_CONTROL;
+       else if (!strcmp(maskstr, "CHANGE"))
+               return CHANGE;
+       else if (!strcmp(maskstr, "D"))
+               return DELETE;
+       else if (!strcmp(maskstr, "READ"))
+               return EREAD;
+       else {
+               len = strlen(maskstr);
+               lmask = maskstr;
+               for (i = 0; i < len; ++i, ++lmask) {
+                       if (*lmask == 'R')
+                               maskval |= EREAD;
+                       else if (*lmask == 'W')
+                               maskval |= EWRITE;
+                       else if (*lmask == 'X')
+                               maskval |= EXEC;
+                       else if (*lmask == 'D')
+                               maskval |= DELETE;
+                       else if (*lmask == 'P')
+                               maskval |= WRITE_DAC;
+                       else if (*lmask == 'O')
+                               maskval |= WRITE_OWNER;
+                       else
+                               return 0;
+               }
+               return maskval;
+       }
+
+       return 0;
+}
+
+static int
+verify_ace_mask(char *maskstr, uint32_t *maskval)
+{
+       char *invalflag;
+
+       if (strstr(maskstr, "0x") || !strcmp(maskstr, "DELDHLD")) {
+               *maskval = strtol(maskstr, &invalflag, 16);
+               if (!invalflag) {
+                       printf("%s: Invalid mask: %s\n", __func__, maskstr);
+                       return 1;
+               }
+       } else
+               *maskval = ace_mask_value(maskstr);
+
+       if (!*maskval) {
+               printf("%s: Invalid mask %s and value: 0x%x\n",
+                       __func__, maskstr, *maskval);
+               return 1;
+       }
+
+       return 0;
+}
+
+static struct cifs_ace **
+build_cmdline_aces(char **arrptr, int numcaces)
+{
+       int i, rc = 0;
+       char *acesid, *acetype, *aceflag, *acemask;
+       struct cifs_ace **cacesptr;
+
+       cacesptr = (struct cifs_ace **)malloc(numcaces *
+                               sizeof(struct cifs_aces *));
+       if (!cacesptr) {
+               printf("%s: Error %d allocating ACE array", __func__, errno);
+               return NULL;
+       }
+
+       for (i = 0; i < numcaces; ++i) {
+               acesid = strtok(arrptr[i], ":");
+               acetype = strtok(NULL, "/");
+               aceflag = strtok(NULL, "/");
+               acemask = strtok(NULL, "/");
+
+               if (!acesid || !acetype || !aceflag || !acemask) {
+                       printf("%s: Incomplete ACE: %s\n", __func__, arrptr[i]);
+                       rc = 1;
+                       goto build_cmdline_aces_ret;
+               }
+
+               cacesptr[i] = malloc(sizeof(struct cifs_ace));
+               if (!cacesptr[i]) {
+                       printf("%s: ACE alloc error %d\n", __func__, errno);
+                       rc = errno;
+                       goto build_cmdline_aces_ret;
+               }
+
+               if (verify_ace_sid(acesid, &cacesptr[i]->sid)) {
+                       printf("%s: Invalid SID: %s\n", __func__, arrptr[i]);
+                       rc = 1;
+                       goto build_cmdline_aces_ret;
+               }
+
+               if (verify_ace_type(acetype, &cacesptr[i]->type)) {
+                       printf("%s: Invalid ACE type: %s\n",
+                                       __func__, arrptr[i]);
+                       rc = 1;
+                       goto build_cmdline_aces_ret;
+               }
+
+               if (verify_ace_flags(aceflag, &cacesptr[i]->flags)) {
+                       printf("%s: Invalid ACE flag: %s\n",
+                               __func__, arrptr[i]);
+                       rc = 1;
+                       goto build_cmdline_aces_ret;
+               }
+
+               if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
+                       printf("%s: Invalid ACE mask: %s\n",
+                               __func__, arrptr[i]);
+                       rc = 1;
+                       goto build_cmdline_aces_ret;
+               }
+
+               cacesptr[i]->size = 1 + 1 + 2 + 4 + 1 + 1 + 6 +
+                               (cacesptr[i]->sid.num_subauth * 4);
+       }
+       return cacesptr;
+
+build_cmdline_aces_ret:
+       for (; i >= 0; --i)
+               free(cacesptr[i]);
+       free(cacesptr);
+       return NULL;
+}
+
+static char **
+parse_cmdline_aces(char *optarg, int numcaces)
+{
+       int i = 0, len;
+       char *acestr, *vacestr, **arrptr = NULL;
+
+       errno = EINVAL;
+       arrptr = (char **)malloc(numcaces * sizeof(char *));
+       if (!arrptr) {
+               printf("%s: Error %d allocating char array\n", __func__, errno);
+               return NULL;
+       }
+
+       while (i < numcaces) {
+               acestr = strtok(optarg, ","); /* everything before , */
+               if (acestr) {
+                       vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
+                       if (vacestr) {
+                               vacestr = strchr(vacestr, ':');
+                               if (vacestr)
+                                       ++vacestr; /* go past : */
+                               if (vacestr) {
+                                       len = strlen(vacestr);
+                                       arrptr[i] = malloc(len + 1);
+                                       if (!arrptr[i])
+                                               goto parse_cmdline_aces_ret;
+                                       strcpy(arrptr[i], vacestr);
+                                       ++i;
+                               } else
+                                       goto parse_cmdline_aces_ret;
+                       } else
+                               goto parse_cmdline_aces_ret;
+               } else
+                       goto parse_cmdline_aces_ret;
+               optarg = NULL;
+       }
+       errno = 0;
+       return arrptr;
+
+parse_cmdline_aces_ret:
+       printf("%s: Error %d parsing ACEs\n", __func__, errno);
+       for (;  i >= 0; --i)
+               free(arrptr[i]);
+       free(arrptr);
+       return NULL;
+}
+
+static unsigned int
+get_numcaces(const char *optarg)
+{
+       int i, len;
+       unsigned int numcaces = 1;
+
+       if (!optarg)
+               return 0;
+
+       len = strlen(optarg);
+       for (i = 0; i < len; ++i) {
+               if (*(optarg + i) == ',')
+                       ++numcaces;
+       }
+
+       return numcaces;
+}
+
+static int
+setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
+               ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
+               struct cifs_ace **cacesptr, int numcaces,
+               int maction)
+{
+       int rc = 1;
+
+       switch (maction) {
+       case 0:
+               rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
+                               numfaces, cacesptr, numcaces);
+               break;
+       case 1:
+               rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
+                               numfaces, cacesptr, numcaces);
+               break;
+       case 2:
+               rc = ace_add(pntsd, npntsd, bufsize, facesptr,
+                               numfaces, cacesptr, numcaces);
+               break;
+       case 3:
+               rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
+               break;
+       default:
+               printf("%s: Invalid action: %d\n", __func__, maction);
+               break;
+       }
+
+       return rc;
+}
+
+static void
+setcifsacl_usage(void)
+{
+       fprintf(stderr,
+       "%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
+               prog);
+       fprintf(stderr, "Usage: %s option <list_of_ACEs> <file_name>\n", prog);
+       fprintf(stderr, "Valid options:\n");
+       fprintf(stderr, "\t-v   Version of the program\n");
+       fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
+       fprintf(stderr,
+       "\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr,
+       "\t-D   Delete ACE(s), separated by a comma, from an ACL\n");
+       fprintf(stderr,
+       "\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr,
+       "\t-M   Modify ACE(s), separated by a comma, in an ACL\n");
+       fprintf(stderr,
+       "\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
+       fprintf(stderr,
+       "\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
+       fprintf(stderr,
+       "\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
+       fprintf(stderr, "\nRefer to setcifsacl(8) manpage for details\n");
+}
+
+int
+main(const int argc, char *const argv[])
+{
+       int i, rc, c, numcaces, numfaces, maction = -1;
+       ssize_t attrlen, bufsize = BUFSIZE;
+       char *filename, *attrval, **arrptr = NULL;
+       struct cifs_ctrl_acl *daclptr = NULL;
+       struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
+       struct cifs_ntsd *ntsdptr = NULL;
+
+       openlog(prog, 0, LOG_DAEMON);
+
+       c = getopt(argc, argv, "v:D:M:a:S:?");
+       switch (c) {
+       case 'v':
+               printf("Version: %s\n", VERSION);
+               goto out;
+       case 'D':
+               maction = 0;
+               break;
+       case 'M':
+               maction = 1;
+               break;
+       case 'a':
+               maction = 2;
+               break;
+       case 'S':
+               maction = 3;
+               break;
+       case '?':
+               setcifsacl_usage();
+               return 0;
+       default:
+               break;
+       }
+
+       if (argc != 4) {
+               setcifsacl_usage();
+               return -1;
+       }
+       filename = argv[3];
+       
+       numcaces = get_numcaces(optarg);
+       if (!numcaces) {
+               printf("%s: No valid ACEs specified\n", __func__);
+               return -1;
+       }
+
+       arrptr = parse_cmdline_aces(optarg, numcaces);
+       if (!arrptr)
+               goto setcifsacl_numcaces_ret;
+
+       cacesptr = build_cmdline_aces(arrptr, numcaces);
+       if (!cacesptr)
+               goto setcifsacl_cmdlineparse_ret;
+
+cifsacl:
+       if (bufsize >= XATTR_SIZE_MAX) {
+               printf("%s: Buffer size %ld exceeds max size of %d\n",
+                               __func__, bufsize, XATTR_SIZE_MAX);
+               goto setcifsacl_cmdlineverify_ret;
+       }
+
+       attrval = malloc(bufsize * sizeof(char));
+       if (!attrval) {
+               printf("error allocating memory for attribute value buffer\n");
+               goto setcifsacl_cmdlineverify_ret;
+       }
+
+       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);
+                       goto setcifsacl_getx_ret;
+               }
+       }
+
+       numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
+       if (!numfaces && maction != 2) { /* if we are not adding aces */
+               printf("%s: Empty DACL\n", __func__);
+               goto setcifsacl_facenum_ret;
+       }
+
+       facesptr = build_fetched_aces((char *)daclptr, numfaces);
+       if (!facesptr)
+               goto setcifsacl_facenum_ret;
+
+       bufsize = 0;
+       rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
+               facesptr, numfaces, cacesptr, numcaces, maction);
+       if (rc)
+               goto setcifsacl_action_ret;
+
+       attrlen = setxattr(filename, ATTRNAME, ntsdptr, bufsize, 0);
+       if (attrlen == -1)
+               printf("%s: setxattr error: %s\n", __func__, strerror(errno));
+       goto setcifsacl_facenum_ret;
+
+out:
+       return 0;
+
+setcifsacl_action_ret:
+       free(ntsdptr);
+
+setcifsacl_facenum_ret:
+       for (i = 0; i < numfaces; ++i)
+               free(facesptr[i]);
+       free(facesptr);
+
+setcifsacl_getx_ret:
+       free(attrval);
+
+setcifsacl_cmdlineverify_ret:
+       for (i = 0; i < numcaces; ++i)
+               free(cacesptr[i]);
+       free(cacesptr);
+
+setcifsacl_cmdlineparse_ret:
+       for (i = 0; i < numcaces; ++i)
+               free(arrptr[i]);
+       free(arrptr);
+
+setcifsacl_numcaces_ret:
+       return -1;
+}
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to