[PATCH] Add support for setting owner and group in ntsd
Boris Protopopov
boris.v.protopopov at gmail.com
Thu Jan 9 16:07:10 UTC 2020
Yes, there is a patch that I have recently posted to linux-cifs and
linux-kernel list (subject line "Add support for setting owner info,
dos attributes, and create time") that enable setting owner/group in
ntsd, file native attributes, and file create time.
Best regards, Boris Protopopov.
On Wed, Jan 8, 2020 at 3:42 PM Pavel Shilovsky <piastryyy at gmail.com> wrote:
>
> пн, 6 янв. 2020 г. в 08:31, Boris Protopopov <boris.v.protopopov at gmail.com>:
> >
> > Extend setcifsacl utility to allow setting owner and group SIDs
> > in the security descriptor in addition to setting ACLs. This is
> > a user-friendly intefrace for setting owner and group SIDs that
> > takes advantage of the recent extensions in the CIFS kernel
> > client, and it complements setting raw values via setfattr.
> >
> > Signed-off-by: Boris Protopopov <boris.v.protopopov at gmail.com>
>
> Thanks for the patch. Could you clarify which recent changes in the
> CIFS kernel client are referenced in the patch description?
>
> > ---
> > cifsacl.h | 4 +-
> > setcifsacl.c | 253 ++++++++++++++++++++++++++++++++++++++++++++----------
> > setcifsacl.rst.in | 27 ++++--
> > 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 at BUILTIN" <file_name>
> > +
> > *****
> > NOTES
> > *****
> > --
> > 2.14.5
> >
>
>
> --
> Best regards,
> Pavel Shilovsky
More information about the samba-technical
mailing list