summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cifsacl.h4
-rw-r--r--setcifsacl.c253
-rw-r--r--setcifsacl.rst.in27
3 files changed, 235 insertions, 49 deletions
diff --git a/cifsacl.h b/cifsacl.h
index ca72dd4..bd0c695 100644
--- a/cifsacl.h
+++ b/cifsacl.h
@@ -26,7 +26,9 @@
#define _CIFSACL_H
#define BUFSIZE 1024
-#define ATTRNAME "system.cifs_acl"
+#define ATTRNAME "system.cifs_acl"
+#define ATTRNAME_ACL ATTRNAME
+#define ATTRNAME_NTSD "system.cifs_ntsd"
#define MAX_NUM_AUTHS 6
diff --git a/setcifsacl.c b/setcifsacl.c
index 9a301e2..6e5a633 100644
--- a/setcifsacl.c
+++ b/setcifsacl.c
@@ -44,7 +44,9 @@ enum setcifsacl_actions {
ActDelete,
ActModify,
ActAdd,
- ActSet
+ ActSetAcl,
+ ActSetOwner,
+ ActSetGroup
};
static void *plugin_handle;
@@ -140,6 +142,90 @@ copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
return bufsize;
}
+/*
+ * 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
+ */
+static ssize_t
+copy_sec_desc_with_sid(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
+ struct cifs_sid *sid, int maction)
+{
+ int size, daclsize;
+ int osidoffset, gsidoffset, dacloffset;
+ int nosidoffset, ngsidoffset, ndacloffset, nsidssize;
+ 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;
+
+ /* copy security descriptor control portion */
+ osidoffset = le32toh(pntsd->osidoffset);
+ gsidoffset = le32toh(pntsd->gsidoffset);
+ dacloffset = le32toh(pntsd->dacloffset);
+ /*
+ * the size of the owner or group sid might be different from the old
+ * one, so the group sid offest might change, and if the owner is
+ * positioned before the DACL, the dacl offset might change as well;
+ * note however, that the owner sid offset does not change
+ */
+ nosidoffset = osidoffset;
+ size = sizeof(struct cifs_ntsd);
+ pnntsd->revision = pntsd->revision;
+ pnntsd->type = pntsd->type;
+ pnntsd->osidoffset = pntsd->osidoffset;
+ bufsize = size;
+
+ /* set the pointers for source sids */
+ if (maction == ActSetOwner) {
+ owner_sid_ptr = sid;
+ group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidoffset);
+ }
+ if (maction == ActSetGroup) {
+ owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidoffset);
+ group_sid_ptr = sid;
+ }
+
+ dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+ daclsize = le16toh(dacl_ptr->size) + sizeof(struct cifs_ctrl_acl);
+
+ /* copy owner sid */
+ nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + nosidoffset);
+ size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
+ bufsize += size;
+ nsidssize = size;
+
+ /* copy group sid */
+ ngsidoffset = nosidoffset + size;
+ ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + ngsidoffset);
+ pnntsd->gsidoffset = htole32(ngsidoffset);
+ size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
+ bufsize += size;
+ 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;
+
+ /*
+ * add DACL size (control portion and the array of aces) to the
+ * buffer size
+ */
+ bufsize += daclsize;
+
+ return bufsize;
+}
+
static int
copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
{
@@ -788,7 +874,7 @@ setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
rc = ace_add(pntsd, npntsd, bufsize, facesptr,
numfaces, cacesptr, numcaces);
break;
- case ActSet:
+ case ActSetAcl:
rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
break;
default:
@@ -803,9 +889,10 @@ static void
setcifsacl_usage(const char *prog)
{
fprintf(stderr,
- "%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
+ "%s: Alter CIFS/NTFS ACL or owner/group in a security descriptor of a file object\n",
+ prog);
+ fprintf(stderr, "Usage: %s option [<list_of_ACEs>|<SID>] <file_name>\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");
@@ -825,21 +912,32 @@ setcifsacl_usage(const char *prog)
"\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,
+ "\n\t-o Set owner using specified SID (name or raw format)\n");
+ fprintf(stderr,
+ "\tsetcifsacl -o \"Administrator\" <file_name>\n");
+ fprintf(stderr,
+ "\n\t-g Set group using specified SID (name or raw format)\n");
+ fprintf(stderr,
+ "\tsetcifsacl -g \"Administrators\" <file_name>\n");
fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
}
int
main(const int argc, char *const argv[])
{
- int i, rc, c, numcaces, numfaces;
+ int i, rc, c, numcaces = 0, numfaces = 0;
enum setcifsacl_actions maction = ActUnknown;
ssize_t attrlen, bufsize = BUFSIZE;
- char *ace_list, *filename, *attrval, **arrptr = NULL;
+ char *ace_list = NULL, *filename = NULL, *attrval = NULL,
+ **arrptr = NULL, *sid_str = NULL;
struct cifs_ctrl_acl *daclptr = NULL;
struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
struct cifs_ntsd *ntsdptr = NULL;
+ struct cifs_sid sid;
+ char *attrname = ATTRNAME_ACL;
- c = getopt(argc, argv, "hvD:M:a:S:");
+ c = getopt(argc, argv, "hvD:M:a:S:o:g:");
switch (c) {
case 'D':
maction = ActDelete;
@@ -854,9 +952,19 @@ main(const int argc, char *const argv[])
ace_list = optarg;
break;
case 'S':
- maction = ActSet;
+ maction = ActSetAcl;
ace_list = optarg;
break;
+ case 'o':
+ maction = ActSetOwner;
+ sid_str = optarg;
+ attrname = ATTRNAME_NTSD;
+ break;
+ case 'g':
+ maction = ActSetGroup;
+ sid_str = optarg;
+ attrname = ATTRNAME_NTSD;
+ break;
case 'h':
setcifsacl_usage(basename(argv[0]));
return 0;
@@ -875,11 +983,16 @@ main(const int argc, char *const argv[])
}
filename = argv[3];
- if (!ace_list) {
+ if (!ace_list && maction != ActSetOwner && maction != ActSetGroup) {
printf("%s: No valid ACEs specified\n", __func__);
return -1;
}
+ if (!sid_str && (maction == ActSetOwner || maction == ActSetGroup)) {
+ printf("%s: No valid SIDs specified\n", __func__);
+ return -1;
+ }
+
if (init_plugin(&plugin_handle)) {
fprintf(stderr, "WARNING: unable to initialize idmapping "
"plugin. Only \"raw\" SID strings will be "
@@ -889,16 +1002,24 @@ main(const int argc, char *const argv[])
plugin_loaded = true;
}
- numcaces = get_numcaces(ace_list);
-
- arrptr = parse_cmdline_aces(ace_list, numcaces);
- if (!arrptr)
- goto setcifsacl_numcaces_ret;
+ if (maction == ActSetOwner || maction == ActSetGroup) {
+ /* parse the sid */
+ if (setcifsacl_str_to_sid(sid_str, &sid)) {
+ printf("%s: failed to parce \'%s\' as SID\n", __func__,
+ sid_str);
+ goto setcifsacl_numcaces_ret;
+ }
+ } else {
+ numcaces = get_numcaces(ace_list);
- cacesptr = build_cmdline_aces(arrptr, numcaces);
- if (!cacesptr)
- goto setcifsacl_cmdlineparse_ret;
+ arrptr = parse_cmdline_aces(ace_list, 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 %zd exceeds max size of %d\n",
@@ -912,7 +1033,7 @@ cifsacl:
goto setcifsacl_cmdlineverify_ret;
}
- attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
+ attrlen = getxattr(filename, attrname, attrval, bufsize);
if (attrlen == -1) {
if (errno == ERANGE) {
free(attrval);
@@ -924,26 +1045,64 @@ cifsacl:
}
}
- numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
- if (!numfaces && maction != ActAdd) { /* if we are not adding aces */
- printf("%s: Empty DACL\n", __func__);
- goto setcifsacl_facenum_ret;
- }
+ if (maction == ActSetOwner || maction == ActSetGroup) {
+ struct cifs_ntsd *pfntsd = (struct cifs_ntsd *)attrval;
+ int dacloffset = le32toh(pfntsd->dacloffset);
+ struct cifs_ctrl_acl *daclinfo =
+ (struct cifs_ctrl_acl *)(attrval + dacloffset);
+ int numaces = le16toh(daclinfo->num_aces);
+ int acessize = le32toh(daclinfo->size);
+ size_t faceoffset, naceoffset;
+ char *faceptr, *naceptr;
- facesptr = build_fetched_aces((char *)daclptr, numfaces);
- if (!facesptr)
- goto setcifsacl_facenum_ret;
+ /*
+ * this allocates large enough buffer for max sid size and the
+ * dacl info from the fetched security descriptor
+ */
+ rc = alloc_sec_desc(pfntsd, &ntsdptr, numaces, &faceoffset);
+ if (rc)
+ goto setcifsacl_numcaces_ret;
- bufsize = 0;
- rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
- facesptr, numfaces, cacesptr, numcaces, maction);
- if (rc)
- goto setcifsacl_action_ret;
+ /*
+ * copy the control structures from the fetched descriptor, the
+ * sid specified by the user, and adjust the offsets/move dacl
+ * control structure if needed
+ */
+ bufsize = copy_sec_desc_with_sid(pfntsd, ntsdptr, &sid,
+ maction);
+
+ /* copy aces verbatim as they have not changed */
+ faceptr = attrval + faceoffset;
+ naceoffset = le32toh(ntsdptr->dacloffset) +
+ sizeof(struct cifs_ctrl_acl);
+ naceptr = (char *)ntsdptr + naceoffset;
+ memcpy(naceptr, faceptr, acessize);
+ } else {
+ bufsize = 0;
+
+ numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen,
+ &daclptr);
+ if (!numfaces && maction != ActAdd) {
+ /* 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;
- attrlen = setxattr(filename, ATTRNAME, ntsdptr, 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;
+ goto setcifsacl_action_ret;
}
if (plugin_loaded)
@@ -951,25 +1110,33 @@ cifsacl:
return 0;
setcifsacl_action_ret:
- free(ntsdptr);
+ if (ntsdptr)
+ free(ntsdptr);
setcifsacl_facenum_ret:
- for (i = 0; i < numfaces; ++i)
- free(facesptr[i]);
- free(facesptr);
+ if (facesptr) {
+ for (i = 0; i < numfaces; ++i)
+ free(facesptr[i]);
+ free(facesptr);
+ }
setcifsacl_getx_ret:
- free(attrval);
+ if (attrval)
+ free(attrval);
setcifsacl_cmdlineverify_ret:
- for (i = 0; i < numcaces; ++i)
- free(cacesptr[i]);
- free(cacesptr);
+ if (cacesptr) {
+ for (i = 0; i < numcaces; ++i)
+ free(cacesptr[i]);
+ free(cacesptr);
+ }
setcifsacl_cmdlineparse_ret:
- free(arrptr);
+ if (arrptr)
+ free(arrptr);
setcifsacl_numcaces_ret:
- exit_plugin(plugin_handle);
+ if (plugin_loaded)
+ exit_plugin(plugin_handle);
return -1;
}
diff --git a/setcifsacl.rst.in b/setcifsacl.rst.in
index de9c758..985af7c 100644
--- a/setcifsacl.rst.in
+++ b/setcifsacl.rst.in
@@ -2,16 +2,16 @@
setcifsacl
==========
-------------------------------------------------------------------------------------------------
-Userspace helper to alter an ACL in a security descriptor for Common Internet File System (CIFS)
-------------------------------------------------------------------------------------------------
+-------------------------------------------------------------------------------------------------------------------
+Userspace helper to alter an ACL or owner/group SID in a security descriptor for Common Internet File System (CIFS)
+-------------------------------------------------------------------------------------------------------------------
:Manual section: 1
********
SYNOPSIS
********
- setcifsacl [-v|-a|-D|-M|-S] "{one or more ACEs}" {file system object}
+ setcifsacl [-v|-a|-D|-M|-S|-o|-g] "{one or more ACEs or a SID}" {file system object}
***********
DESCRIPTION
@@ -20,7 +20,7 @@ DESCRIPTION
This tool is part of the cifs-utils suite.
``setcifsacl`` is a userspace helper program for the Linux CIFS client
-file system. It is intended to alter an ACL of a security descriptor
+file system. It is intended to alter an ACL or set owner/group SID of a security descriptor
for a file system object. Whether a security descriptor to be set is
applied or not is determined by the CIFS/SMB server.
@@ -55,6 +55,13 @@ OPTIONS
Set an ACL of security descriptor with the list of ACEs Existing ACL
is replaced entirely with the specified ACEs.
+-o
+ Set owner SID to one specified as a command line argument.
+
+-g
+ Set group SID to one specified as a command line argument.
+
+ The owner/group SID can be specified as a name or a raw SID value.
Every ACE entry starts with "ACL:" One or more ACEs are specified
within double quotes. Multiple ACEs are separated by a comma.
@@ -93,6 +100,16 @@ Set an ACL
setcifsacl -S "ACL:CIFSTESTDOM\Administrator:0x0/0x0/FULL,ACL:CIFSTESTDOM\user2:0x0/0x0/FULL" <file_name>
+Set owner SID
+=============
+
+ setcifsacl -o "S-1-5-21-3338130290-3403600371-1423429424-2102" <file_name>
+
+Set group SID
+=============
+
+ setcifsacl -g "Administrators@BUILTIN" <file_name>
+
*****
NOTES
*****