summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cifsacl.h57
-rw-r--r--getcifsacl.c217
-rw-r--r--getcifsacl.rst.in4
-rw-r--r--setcifsacl.c695
-rw-r--r--setcifsacl.rst.in27
5 files changed, 719 insertions, 281 deletions
diff --git a/cifsacl.h b/cifsacl.h
index bd0c695..20309ef 100644
--- a/cifsacl.h
+++ b/cifsacl.h
@@ -25,13 +25,19 @@
#ifndef _CIFSACL_H
#define _CIFSACL_H
-#define BUFSIZE 1024
-#define ATTRNAME "system.cifs_acl"
-#define ATTRNAME_ACL ATTRNAME
-#define ATTRNAME_NTSD "system.cifs_ntsd"
+#define BUFSIZE 1024
+#define ATTRNAME "system.cifs_acl"
+#define ATTRNAME_ACL ATTRNAME
+#define ATTRNAME_NTSD "system.cifs_ntsd"
+#define ATTRNAME_NTSD_FULL "system.cifs_ntsd_full"
#define MAX_NUM_AUTHS 6
+typedef enum {
+ ACE_KIND_DACL,
+ ACE_KIND_SACL
+} ace_kinds;
+
/* File specific rights */
#define READ_DATA 0x00000001 /* R */
#define WRITE_DATA 0x00000002 /* W */
@@ -82,17 +88,36 @@
/* WA | WEA | A | W */
#define ALL_WRITE_BITS 0x40000116
-#define OBJECT_INHERIT_FLAG 0x01 /* OI */
-#define CONTAINER_INHERIT_FLAG 0x02 /* CI */
-#define NO_PROPAGATE_INHERIT_FLAG 0x04 /* NP */
-#define INHERIT_ONLY_FLAG 0x08 /* IO */
-#define INHERITED_ACE_FLAG 0x10 /* I */
-#define VFLAGS (OBJECT_INHERIT_FLAG|CONTAINER_INHERIT_FLAG|NO_PROPAGATE_INHERIT_FLAG|INHERIT_ONLY_FLAG|INHERITED_ACE_FLAG)
-
-#define ACCESS_ALLOWED 0 /* ALLOWED */
-#define ACCESS_DENIED 1 /* DENIED */
-#define ACCESS_ALLOWED_OBJECT 5 /* OBJECT_ALLOWED */
-#define ACCESS_DENIED_OBJECT 6 /* OBJECT_DENIED */
+/* R | W | A | REA | WEA | E | DC | RA | EA | D | RC | P | O */
+#define ALL_ACCESS_BITS 0x000f01ff
+
+/* ace flags */
+#define OBJECT_INHERIT_FLAG 0x01 /* OI */
+#define CONTAINER_INHERIT_FLAG 0x02 /* CI */
+#define NO_PROPAGATE_INHERIT_FLAG 0x04 /* NP */
+#define INHERIT_ONLY_FLAG 0x08 /* IO */
+#define INHERITED_ACE_FLAG 0x10 /* I */
+#define DACL_VFLAGS (OBJECT_INHERIT_FLAG|CONTAINER_INHERIT_FLAG|NO_PROPAGATE_INHERIT_FLAG|INHERIT_ONLY_FLAG|INHERITED_ACE_FLAG)
+
+#define SUCCESSFUL_ACCESS 0x40 /* SA */
+#define FAILED_ACCESS 0x80 /* FA */
+#define SACL_VFLAGS (SUCCESSFUL_ACCESS | FAILED_ACCESS)
+
+/* ace types */
+#define ACCESS_ALLOWED 0 /* ALLOWED */
+#define ACCESS_DENIED 1 /* DENIED */
+#define SYSTEM_AUDIT 2 /* AUDIT */
+#define ACCESS_ALLOWED_OBJECT 5 /* OBJECT_ALLOWED */
+#define ACCESS_DENIED_OBJECT 6 /* OBJECT_DENIED */
+#define SYSTEM_AUDIT_OBJECT 7 /* AUDIT_OBJECT */
+#define SYSTEM_AUDIT_CALLBACK 13 /* AUDIT_CALLBACK */
+#define SYSTEM_AUDIT_CALLBACK_OBJECT 15 /* AUDIT_CALLBACK_OBJECT */
+#define SYSTEM_MANDATORY_LABEL 17 /* MANDATORY_LABEL */
+#define SYSTEM_RESOURCE_ATTRIBUTE 18 /* RESOURCE_ATTRIBUTE */
+#define SYSTEM_SCOPED_POLICY_ID 19 /* SCOPED_POLICY_ID */
+
+#define DACL_VTYPES (ACCESS_ALLOWED | ACCESS_DENIED | ACCESS_ALLOWED_OBJECT | ACCESS_DENIED_OBJECT)
+#define SACL_VTYPES (SYSTEM_AUDIT | SYSTEM_AUDIT_OBJECT | SYSTEM_AUDIT_CALLBACK | SYSTEM_AUDIT_CALLBACK_OBJECT | SYSTEM_MANDATORY_LABEL | SYSTEM_RESOURCE_ATTRIBUTE | SYSTEM_SCOPED_POLICY_ID)
#define COMPSID 0x1
#define COMPTYPE 0x2
@@ -100,6 +125,8 @@
#define COMPMASK 0x8
#define COMPALL (COMPSID|COMPTYPE|COMPFLAG|COMPMASK)
+#define DEFAULT_ACL_REVISION 0x2
+
/*
* While not indicated here, the structs below represent on-the-wire data
* structures. Any multi-byte values are expected to be little-endian!
diff --git a/getcifsacl.c b/getcifsacl.c
index 89851f6..1c01062 100644
--- a/getcifsacl.c
+++ b/getcifsacl.c
@@ -47,6 +47,11 @@ static bool raw = false;
static void
print_each_ace_mask(uint32_t mask)
{
+ if ((mask & ALL_ACCESS_BITS) == ALL_ACCESS_BITS) {
+ printf("RWXDPO");
+ return;
+ }
+
if ((mask & ALL_READ_BITS) && ((mask & EREAD) != EREAD &&
(mask & OREAD) != OREAD && (mask & BREAD) != BREAD)) {
printf("0x%x", mask);
@@ -74,32 +79,48 @@ print_each_ace_mask(uint32_t mask)
}
static void
-print_ace_mask(uint32_t mask, int raw)
+print_ace_mask(uint32_t mask, int raw, ace_kinds ace_kind)
{
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);
-
+ switch (ace_kind) {
+ case ACE_KIND_SACL:
+ 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
+ print_each_ace_mask(mask);
+ break;
+ case ACE_KIND_DACL:
+ default:
+ 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);
+ break;
+ }
printf("\n");
return;
}
static void
-print_ace_flags(uint8_t flags, int raw)
+print_ace_flags(uint8_t flags, int raw, ace_kinds ace_kind)
{
bool mflags = false;
@@ -108,37 +129,54 @@ print_ace_flags(uint8_t flags, int raw)
return;
}
- if (flags & OBJECT_INHERIT_FLAG) {
- 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
+ switch (ace_kind) {
+ case ACE_KIND_SACL:
+ if (flags & SUCCESSFUL_ACCESS) {
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
+ printf("SA");
+ }
+ if (flags & FAILED_ACCESS) {
+ if (mflags)
+ printf("|");
+ else
+ mflags = true;
+ printf("FA");
+ }
+ break;
+ case ACE_KIND_DACL:
+ if (flags & OBJECT_INHERIT_FLAG) {
mflags = true;
- printf("I");
+ 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");
+ }
+ break;
}
if (!mflags)
@@ -166,6 +204,27 @@ print_ace_type(uint8_t acetype, int raw)
case ACCESS_DENIED_OBJECT:
printf("OBJECT_DENIED");
break;
+ case SYSTEM_AUDIT:
+ printf("AUDIT");
+ break;
+ case SYSTEM_AUDIT_OBJECT:
+ printf("AUDIT_OBJECT");
+ break;
+ case SYSTEM_AUDIT_CALLBACK:
+ printf("AUDIT_CALLBACK");
+ break;
+ case SYSTEM_AUDIT_CALLBACK_OBJECT:
+ printf("AUDIT_CALLBACK_OBJECT");
+ break;
+ case SYSTEM_MANDATORY_LABEL:
+ printf("MANDATORY_LABEL");
+ break;
+ case SYSTEM_RESOURCE_ATTRIBUTE:
+ printf("RESOURCE_ATTRIBUTE");
+ break;
+ case SYSTEM_SCOPED_POLICY_ID:
+ printf("SCOPED_POLICY_ID");
+ break;
default:
printf("UNKNOWN");
break;
@@ -214,7 +273,7 @@ print_sid_raw:
}
static void
-print_ace(struct cifs_ace *pace, char *end_of_acl, int raw)
+print_ace(struct cifs_ace *pace, char *end_of_acl, int raw, ace_kinds ace_kind)
{
uint16_t size;
@@ -237,15 +296,15 @@ print_ace(struct cifs_ace *pace, char *end_of_acl, int raw)
printf(":");
print_ace_type(pace->type, raw);
printf("/");
- print_ace_flags(pace->flags, raw);
+ print_ace_flags(pace->flags, raw, ace_kind);
printf("/");
- print_ace_mask(le32toh(pace->access_req), raw);
+ print_ace_mask(le32toh(pace->access_req), raw, ace_kind);
return;
}
static void
-parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw)
+ parse_acl(struct cifs_ctrl_acl *pacl, char *end_of_acl, int raw, ace_kinds ace_kind)
{
int i;
int num_aces = 0;
@@ -253,20 +312,20 @@ parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw)
char *acl_base;
struct cifs_ace *pace;
- if (!pdacl)
+ if (!pacl)
return;
- if (end_of_acl < (char *)pdacl + le16toh(pdacl->size))
+ if (end_of_acl < (char *)pacl + le16toh(pacl->size))
return;
- acl_base = (char *)pdacl;
+ acl_base = (char *)pacl;
acl_size = sizeof(struct cifs_ctrl_acl);
- num_aces = le32toh(pdacl->num_aces);
+ num_aces = le32toh(pacl->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);
+ print_ace(pace, end_of_acl, raw, ace_kind);
acl_base = (char *)pace;
acl_size = le16toh(pace->size);
}
@@ -293,10 +352,10 @@ static int
parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
{
int rc;
- uint32_t dacloffset;
+ uint32_t dacloffset, sacloffset;
char *end_of_acl = ((char *)pntsd) + acl_len;
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
- struct cifs_ctrl_acl *dacl_ptr; /* no need for SACL ptr */
+ struct cifs_ctrl_acl *dacl_ptr, *sacl_ptr;
if (pntsd == NULL)
return -EIO;
@@ -307,6 +366,9 @@ parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
le32toh(pntsd->gsidoffset));
dacloffset = le32toh(pntsd->dacloffset);
dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+ sacloffset = le32toh(pntsd->sacloffset);
+ sacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + sacloffset);
+
printf("REVISION:0x%x\n", le16toh(pntsd->revision));
printf("CONTROL:0x%x\n", le16toh(pntsd->type));
@@ -318,10 +380,19 @@ parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int 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? */
+ if (dacloffset) {
+ printf("DACL:\n");
+ parse_acl(dacl_ptr, end_of_acl, raw, ACE_KIND_DACL);
+ } else {
+ printf("No DACL\n"); /* BB grant all or default perms? */
+ }
+
+ if (sacloffset) {
+ printf("SACL:\n");
+ parse_acl(sacl_ptr, end_of_acl, raw, ACE_KIND_SACL);
+ } else {
+ printf("No SACL\n");
+ }
return 0;
}
@@ -351,6 +422,9 @@ getcifsacl(const char *filename)
size_t bufsize = BUFSIZE;
char *attrval;
int rc = 0;
+ /* use attribute name to fetch the whole descriptor */
+ char *attrname = ATTRNAME_NTSD_FULL;
+
cifsacl:
if (bufsize >= XATTR_SIZE_MAX) {
fprintf(stderr, "buffer to allocate exceeds max size of %d\n",
@@ -364,12 +438,35 @@ cifsacl:
exit(1);
}
- attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
+getxattr:
+ attrlen = getxattr(filename, attrname, attrval, bufsize);
if (attrlen == -1) {
if (errno == ERANGE) {
free(attrval);
bufsize += BUFSIZE;
goto cifsacl;
+ } else if (errno == EIO && !(strcmp(attrname, ATTRNAME_NTSD_FULL))) {
+ /*
+ * attempt to fetch SACL in addition to owner and DACL via
+ * ATTRNAME_NTSD_FULL, fall back to owner/DACL via
+ * ATTRNAME_ACL if not allowed
+ * CIFS client maps STATUS_PRIVILEGE_NOT_HELD to EIO
+ */
+ fprintf(stderr, "WARNING: Insufficient priviledges to fetch SACL for %s\n",
+ filename);
+ fprintf(stderr, " Fetching owner info and DACL only\n");
+ attrname = ATTRNAME_ACL;
+ goto getxattr;
+ } else if (errno == EOPNOTSUPP && !(strcmp(attrname, ATTRNAME_NTSD_FULL))) {
+ /*
+ * no support for fetching SACL, fall back to owner/DACL via
+ * ATTRNAME_ACL
+ */
+ fprintf(stderr, "WARNING: CIFS client does not support fetching SACL for %s\n",
+ filename);
+ fprintf(stderr, " Fetching owner info and DACL only\n");
+ attrname = ATTRNAME_ACL;
+ goto getxattr;
} else {
fprintf(stderr, "Failed to getxattr %s: %s\n", filename,
strerror(errno));
diff --git a/getcifsacl.rst.in b/getcifsacl.rst.in
index ffde968..b7645fa 100644
--- a/getcifsacl.rst.in
+++ b/getcifsacl.rst.in
@@ -20,8 +20,8 @@ DESCRIPTION
This tool is part of the cifs-utils suite.
``getcifsacl`` is a userspace helper program for the Linux CIFS client
-file system. It is intended to display a security descriptor including
-ACL for a file system object.
+file system. It is intended to display a security descriptor, including
+DACL and SACL for a file system object.
This program uses a plugin to handle the mapping of SIDs to user and
group names. *@pluginpath@* should be a symlink that points to the
diff --git a/setcifsacl.c b/setcifsacl.c
index 6e5a633..db9cf2c 100644
--- a/setcifsacl.c
+++ b/setcifsacl.c
@@ -20,6 +20,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/*
+ * This utility modifies various components of the security descriptor. These
+ * actions require different permissions and different SMB protocol-level flags.
+ * The user needs to make sure the share is mounted using the user credentials
+ * for the user who has appropriate permissions and privileges. The kernel
+ * CIFS client knows which flags to use based on the extended attribute name:
+ * - system.cifs_acl - set dacl only
+ * - system.cifs_ndst - set dacl and owner info
+ * - system.cifs_ntsd_full - set dacl, owner, and sacl
+ *
+ * For simplicity, the utility modifies one component of the descriptor:
+ * owner sid, group sid, DACL, or SACL. The rest of the descriptor is unchanged.
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
@@ -46,7 +60,8 @@ enum setcifsacl_actions {
ActAdd,
ActSetAcl,
ActSetOwner,
- ActSetGroup
+ ActSetGroup,
+ ActSetSacl
};
static void *plugin_handle;
@@ -74,20 +89,142 @@ copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
return size;
}
+static int
+get_cifs_sid_size(const struct cifs_sid *sid)
+{
+ return (2 * sizeof(uint8_t) +
+ sizeof(uint8_t) * NUM_AUTHS +
+ sizeof(uint32_t) * sid->num_subauth);
+}
+
+/*
+ * This function takes a pointer of the fetched (original) descriptor, and
+ * it returns the offset of the ACL in the new descriptor.
+ *
+ * If the original descriptor does not have an ACL, the corresponding offset
+ * is 0, and we need to determine where to place the ACL in the new descriptor.
+ * If SACL offset is zero, and there is DACL (dacloffset is not 0), then we will
+ * put SACL after DACL. If the DACL is not present either, we do not know if the
+ * ACLs should go before or after the owner and group SIDs (see below), and so
+ * we will use the offset right past the group SID.
+ * Similarly, if DACL offset is zero, we will use the offset the past the end
+ * of group SID.
+ * @todo: need to add a command-line argument to know if this is
+ * Azure-style descriptor or a regular-style descriptor
+ */
+static int get_aces_offset(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
+ int dacloffset, sacloffset, acesoffset;
+
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ sacloffset = le32toh(pntsd->sacloffset);
+ if (sacloffset) {
+ acesoffset = sacloffset + sizeof(struct cifs_ctrl_acl);
+ } else {
+ dacloffset = le32toh(pntsd->dacloffset);
+ if (dacloffset) {
+ struct cifs_ctrl_acl *dacl_ptr =
+ (struct cifs_ctrl_acl *)((char *)pntsd +
+ dacloffset);
+ acesoffset = dacloffset +
+ le16toh(dacl_ptr->size) +
+ sizeof(struct cifs_ctrl_acl);
+ } else {
+ int gsidoffset = le32toh(pntsd->gsidoffset);
+ struct cifs_sid *group_sid_ptr =
+ (struct cifs_sid *)((char *)pntsd +
+ gsidoffset);
+ int gsidsize = get_cifs_sid_size(group_sid_ptr);
+ acesoffset = gsidoffset + gsidsize +
+ sizeof(struct cifs_ctrl_acl);
+ }
+ }
+ break;
+ case ACE_KIND_DACL:
+ default:
+ dacloffset = le32toh(pntsd->dacloffset);
+ if (dacloffset) {
+ acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
+ } else {
+ int gsidoffset = le32toh(pntsd->gsidoffset);
+ struct cifs_sid *group_sid_ptr =
+ (struct cifs_sid *)((char *)pntsd +
+ gsidoffset);
+ int gsidsize = get_cifs_sid_size(group_sid_ptr);
+ acesoffset = gsidoffset + gsidsize +
+ sizeof(struct cifs_ctrl_acl);
+ }
+ break;
+ }
+ return acesoffset;
+}
+
+int get_aces_size(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
+ int acloffset, size;
+ struct cifs_ctrl_acl *acl_ptr;
+
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ acloffset = le32toh(pntsd->sacloffset);
+ break;
+ case ACE_KIND_DACL:
+ default:
+ acloffset = le32toh(pntsd->dacloffset);
+ }
+ if (acloffset) {
+ acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + acloffset);
+ size = le16toh(acl_ptr->size);
+ } else {
+ size = 0;
+ }
+ return size;
+}
+
+uint16_t get_acl_revision(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
+ struct cifs_ctrl_acl *acl_ptr;
+ int acloffset;
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ acloffset = le32toh(pntsd->sacloffset);
+ if (acloffset) {
+ acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd +
+ acloffset);
+ return acl_ptr->revision;
+ }
+ /* intentional fall through */
+ case ACE_KIND_DACL:
+ default:
+ acloffset = le32toh(pntsd->dacloffset);
+ if (acloffset) {
+ acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd +
+ acloffset);
+ return acl_ptr->revision;
+ } else {
+ return DEFAULT_ACL_REVISION;
+ }
+ break;
+ }
+}
+
+/*
+ * The actual changes to the ACL specified in ace_kind are performed by the
+ * caller of this function; this function copies/backfills the remaining
+ * relevant compoenents of the security descriptor that remain unchanged.
+ */
static ssize_t
copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
- int numaces, int acessize)
+ int numaces, int acessize, ace_kinds ace_kind)
{
- int size, osidsoffset, gsidsoffset, dacloffset;
+ int size, osidsoffset, gsidsoffset, acloffset, dacloffset;
ssize_t bufsize;
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;
+ struct cifs_ctrl_acl *nacl_ptr, *dacl_ptr;
+ char *ndacl_ptr;
/* copy security descriptor control portion */
osidsoffset = le32toh(pntsd->osidoffset);
gsidsoffset = le32toh(pntsd->gsidoffset);
- dacloffset = le32toh(pntsd->dacloffset);
size = sizeof(struct cifs_ntsd);
pnntsd->revision = pntsd->revision;
@@ -97,26 +234,43 @@ copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
pnntsd->dacloffset = pntsd->dacloffset;
bufsize = size;
- dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
- ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
+ /* owner and group SIDs in the original defscriptor */
+ owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
+ group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
+
+ /* get the offset of the acl control structure to initialize */
+ acloffset = get_aces_offset(pntsd, ace_kind) - sizeof(struct cifs_ctrl_acl);
+ if (ace_kind == ACE_KIND_SACL) {
+ /* copy (unchanged) DACL if present, increment bufsize */
+ dacloffset = le32toh(pntsd->dacloffset);
+ if (dacloffset) {
+ dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+ ndacl_ptr = (char *)pnntsd + dacloffset;
+ size = sizeof(struct cifs_ctrl_acl) + le16toh(dacl_ptr->size);
+ memcpy(ndacl_ptr, (char *)dacl_ptr, size);
+ bufsize += size;
+ }
+ /* initialize SACL offset */
+ pnntsd->sacloffset = acloffset;
+ }
+ nacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + acloffset);
+ nacl_ptr->revision = get_acl_revision(pntsd, ace_kind);
size = acessize + sizeof(struct cifs_ctrl_acl);
- ndacl_ptr->revision = dacl_ptr->revision;
- ndacl_ptr->size = htole16(size);
- ndacl_ptr->num_aces = htole32(numaces);
+ nacl_ptr->size = htole16(size);
+ nacl_ptr->num_aces = htole32(numaces);
bufsize += size;
/* copy owner sid */
- owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
- group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
+
/*
* some servers like Azure return the owner and group SIDs at end rather
* than at the beginning of the ACL so don't want to overwrite the last ACEs
*/
- if (dacloffset <= osidsoffset) {
+ if (acloffset <= osidsoffset) {
/* owners placed at end of ACL */
- nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + dacloffset + size);
- osidsoffset = dacloffset + size;
+ nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + acloffset + size);
+ osidsoffset = acloffset + size;
pnntsd->osidoffset = htole32(osidsoffset);
size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
bufsize += size;
@@ -143,10 +297,9 @@ copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
}
/*
- * This function (and the one above) does not need to set the SACL-related
- * fields, and this works fine because on the SMB protocol level, setting owner
- * info, DACL, and SACL requires one to use separate flags that control which
- * part of the descriptor is begin looked at on the server side
+ * This function does not need to set the SACL-related fields, and this works
+ * fine because the code path calling this function picks the 'system.cifs_ntsd'
+ * attribute name. This name tells Linux CIFS client that SACL is not modified.
*/
static ssize_t
copy_sec_desc_with_sid(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
@@ -187,8 +340,13 @@ copy_sec_desc_with_sid(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
group_sid_ptr = sid;
}
- dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
- daclsize = le16toh(dacl_ptr->size) + sizeof(struct cifs_ctrl_acl);
+ if (dacloffset) {
+ dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+ daclsize = le16toh(dacl_ptr->size) + sizeof(struct cifs_ctrl_acl);
+ } else {
+ dacl_ptr = NULL;
+ daclsize = 0;
+ }
/* copy owner sid */
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + nosidoffset);
@@ -205,18 +363,21 @@ copy_sec_desc_with_sid(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
nsidssize += size;
/* position the dacl control info as in the fetched descriptor */
- if (dacloffset <= osidoffset)
- ndacloffset = dacloffset;
- else
- ndacloffset = nosidoffset + nsidssize;
- ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + ndacloffset);
- pnntsd->dacloffset = htole32(ndacloffset);
-
- /* the DACL control fields do not change */
- ndacl_ptr->revision = dacl_ptr->revision;
- ndacl_ptr->size = dacl_ptr->size;
- ndacl_ptr->num_aces = dacl_ptr->num_aces;
-
+ if (dacloffset) {
+ if (dacloffset <= osidoffset)
+ ndacloffset = dacloffset;
+ else
+ ndacloffset = nosidoffset + nsidssize;
+ ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + ndacloffset);
+ pnntsd->dacloffset = htole32(ndacloffset);
+
+ /* the DACL control fields do not change */
+ ndacl_ptr->revision = dacl_ptr->revision;
+ ndacl_ptr->size = dacl_ptr->size;
+ ndacl_ptr->num_aces = dacl_ptr->num_aces;
+ } else {
+ pnntsd->dacloffset = 0;
+ }
/*
* add DACL size (control portion and the array of aces) to the
* buffer size
@@ -278,25 +439,44 @@ compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
return 1;
}
+/*
+ * This is somewhat suboptimal, but to keep the code simple, we will still
+ * allocate the ACL control headers for DACL and SACL even thought there is
+ * no corresponding ACL (dacloffset = 0 or sacloffset = 0).
+ * When seetting DACL, we allocate sufficient space for the descriptor control
+ * structure, owner and group sids, and the DACL (ACL control structure and
+ * the aces).
+ * When setting SACL, we allocate sufficient space to copy the above components
+ * plus the SACL to be set (ACL controla and aces).
+ */
static int
alloc_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
- int aces, size_t *acesoffset)
+ int aces, size_t *acesoffset, ace_kinds ace_kind)
{
- unsigned int size, acessize, bufsize, dacloffset;
-
- size = sizeof(struct cifs_ntsd) +
- 2 * sizeof(struct cifs_sid) +
- sizeof(struct cifs_ctrl_acl);
-
- dacloffset = le32toh(pntsd->dacloffset);
+ unsigned int size, acessize, bufsize;
+
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ size = sizeof(struct cifs_ntsd) +
+ 2 * sizeof(struct cifs_sid) +
+ sizeof(struct cifs_ctrl_acl) +
+ get_aces_size(pntsd, ACE_KIND_DACL) +
+ sizeof(struct cifs_ctrl_acl);
+ break;
+ case ACE_KIND_DACL:
+ default:
+ size = sizeof(struct cifs_ntsd) +
+ 2 * sizeof(struct cifs_sid) +
+ sizeof(struct cifs_ctrl_acl);
+ break;
+ }
- *acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
+ *acesoffset = get_aces_offset(pntsd, ace_kind);
acessize = aces * sizeof(struct cifs_ace);
bufsize = size + acessize;
-
*npntsd = calloc(1, bufsize);
if (!*npntsd) {
- printf("%s: Memory allocation failure", __func__);
+ fprintf(stderr, "%s: Memory allocation failure", __func__);
return errno;
}
@@ -305,13 +485,13 @@ alloc_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
static int
ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
- struct cifs_ace **cacesptr, int numcaces)
+ struct cifs_ace **cacesptr, int numcaces, ace_kinds ace_kind)
{
int i, rc, size = 0, acessize = 0;
size_t acesoffset;
char *acesptr;
- rc = alloc_sec_desc(pntsd, npntsd, numcaces, &acesoffset);
+ rc = alloc_sec_desc(pntsd, npntsd, numcaces, &acesoffset, ace_kind);
if (rc)
return rc;
@@ -322,7 +502,7 @@ ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
acesptr += size;
}
- *bufsize = copy_sec_desc(pntsd, *npntsd, numcaces, acessize);
+ *bufsize = copy_sec_desc(pntsd, *npntsd, numcaces, acessize, ace_kind);
return 0;
}
@@ -330,14 +510,15 @@ ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
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)
+ struct cifs_ace **cacesptr, int numcaces,
+ ace_kinds ace_kind)
{
int i, rc, numaces, size, acessize = 0;
size_t acesoffset;
char *acesptr;
numaces = numfaces + numcaces;
- rc = alloc_sec_desc(pntsd, npntsd, numaces, &acesoffset);
+ rc = alloc_sec_desc(pntsd, npntsd, numaces, &acesoffset, ace_kind);
if (rc)
return rc;
@@ -353,7 +534,7 @@ ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
acessize += size;
}
- *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize);
+ *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize, ace_kind);
return 0;
}
@@ -361,18 +542,19 @@ ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
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)
+ struct cifs_ace **cacesptr, int numcaces,
+ ace_kinds ace_kind)
{
int i, j, rc, size, acessize = 0;
size_t acesoffset;
char *acesptr;
if (numfaces == 0) {
- printf("%s: No entries to modify", __func__);
+ fprintf(stderr, "%s: No entries to modify", __func__);
return -1;
}
- rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset);
+ rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset, ace_kind);
if (rc)
return rc;
@@ -393,7 +575,7 @@ ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
acessize += size;
}
- *bufsize = copy_sec_desc(pntsd, *npntsd, numfaces, acessize);
+ *bufsize = copy_sec_desc(pntsd, *npntsd, numfaces, acessize, ace_kind);
return 0;
}
@@ -401,23 +583,24 @@ ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
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)
+ struct cifs_ace **cacesptr, int numcaces,
+ ace_kinds ace_kind)
{
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__);
+ fprintf(stderr, "%s: No entries to delete\n", __func__);
return -1;
}
if (numfaces < numcaces) {
- printf("%s: Invalid entries to delete\n", __func__);
+ fprintf(stderr, "%s: Invalid entries to delete\n", __func__);
return -1;
}
- rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset);
+ rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset, ace_kind);
if (rc)
return rc;
@@ -429,7 +612,7 @@ ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
}
if (j == numcaces) {
size = copy_ace((struct cifs_ace *)acesptr,
- facesptr[i]);
+ facesptr[i]);
acessize += size;
acesptr += size;
++numaces;
@@ -437,41 +620,50 @@ ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
}
if (numaces == numfaces) {
- printf("%s: Nothing to delete\n", __func__);
+ fprintf(stderr, "%s: Nothing to delete\n", __func__);
return 1;
}
- *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize);
+ *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize, ace_kind);
return 0;
}
static int
get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
- struct cifs_ctrl_acl **daclptr)
+ struct cifs_ctrl_acl **aclptr, ace_kinds ace_kind)
{
int numfaces = 0;
- uint32_t dacloffset;
- struct cifs_ctrl_acl *ldaclptr;
+ uint32_t acloffset;
+ struct cifs_ctrl_acl *laclptr;
char *end_of_acl = ((char *)pntsd) + acl_len;
- dacloffset = le32toh(pntsd->dacloffset);
- if (!dacloffset)
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ acloffset = le32toh(pntsd->sacloffset);
+ break;
+ case ACE_KIND_DACL:
+ default:
+ acloffset = le32toh(pntsd->dacloffset);
+ break;
+ }
+
+ if (!acloffset)
return 0;
- ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+ laclptr = (struct cifs_ctrl_acl *)((char *)pntsd + acloffset);
/* 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;
+ if (end_of_acl >= (char *)laclptr + le16toh(laclptr->size)) {
+ numfaces = le32toh(laclptr->num_aces);
+ *aclptr = laclptr;
}
return numfaces;
}
static struct cifs_ace **
-build_fetched_aces(char *daclptr, int numfaces)
+build_fetched_aces(char *aclptr, int numfaces)
{
int i, acl_size;
char *acl_base;
@@ -479,12 +671,12 @@ build_fetched_aces(char *daclptr, int numfaces)
facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
if (!facesptr) {
- printf("%s: Error %d allocating ACE array",
+ fprintf(stderr, "%s: Error %d allocating ACE array",
__func__, errno);
return facesptr;
}
- acl_base = daclptr;
+ acl_base = aclptr;
acl_size = sizeof(struct cifs_ctrl_acl);
for (i = 0; i < numfaces; ++i) {
facesptr[i] = malloc(sizeof(struct cifs_ace));
@@ -498,7 +690,7 @@ build_fetched_aces(char *daclptr, int numfaces)
return facesptr;
build_fetched_aces_err:
- printf("%s: Invalid fetched ace\n", __func__);
+ fprintf(stderr, "%s: Invalid fetched ace\n", __func__);
for (i = 0; i < numfaces; ++i)
free(facesptr[i]);
free(facesptr);
@@ -506,75 +698,129 @@ build_fetched_aces_err:
}
static int
-verify_ace_type(char *typestr, uint8_t *typeval)
+verify_ace_type(char *typestr, uint8_t *typeval, ace_kinds ace_kind)
{
int i, len;
char *invaltype;
+ uint8_t ace_type_mask;
+
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ ace_type_mask = SACL_VTYPES;
+ break;
+ case ACE_KIND_DACL:
+ default:
+ ace_type_mask = DACL_VTYPES;
+ break;
+ }
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;
+ /* the type must be a single bit from the bit mask */
+ if (*typeval != (*typeval & ace_type_mask)) {
+ fprintf(stderr, "%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;
+ switch(ace_kind) {
+ case ACE_KIND_SACL:
+ for (i = 0; i < len; ++i)
+ *(typestr + i) = toupper(*(typestr + i));
+ if (!strcmp(typestr, "AUDIT"))
+ *typeval = SYSTEM_AUDIT;
+ else if (!strcmp(typestr, "AUDIT_OBJECT"))
+ *typeval = SYSTEM_AUDIT_OBJECT;
+ else if (!strcmp(typestr, "AUDIT_CALLBACK"))
+ *typeval = SYSTEM_AUDIT_CALLBACK;
+ else if (!strcmp(typestr, "AUDIT_CALLBACK_OBJECT"))
+ *typeval = SYSTEM_AUDIT_CALLBACK_OBJECT;
+ else if (!strcmp(typestr, "MANDATODY_LABEL"))
+ *typeval = SYSTEM_MANDATORY_LABEL;
+ else if (!strcmp(typestr, "RESOURCE_ATTRIBUTE"))
+ *typeval = SYSTEM_RESOURCE_ATTRIBUTE;
+ else if (!strcmp(typestr, "SCOPED_POLICY_ID"))
+ *typeval = SYSTEM_SCOPED_POLICY_ID;
+ else {
+ fprintf(stderr, "%s: Invalid type: %s\n", __func__,
+ typestr);
+ return 1;
+ }
+ break;
+ case ACE_KIND_DACL:
+ default:
+ for (i = 0; i < len; ++i)
+ *(typestr + i) = toupper(*(typestr + i));
+ if (!strcmp(typestr, "ALLOWED"))
+ *typeval = ACCESS_ALLOWED;
+ else if (!strcmp(typestr, "DENIED"))
+ *typeval = ACCESS_DENIED;
+ else if (!strcmp(typestr, "ALLOWED_OBJECT"))
+ *typeval = ACCESS_ALLOWED_OBJECT;
+ else if (!strcmp(typestr, "DENIED_OBJECT"))
+ *typeval = ACCESS_DENIED_OBJECT;