[PATCH] Add support for setting owner and group in ntsd

Pavel Shilovsky piastryyy at gmail.com
Wed Jan 8 20:42:00 UTC 2020


пн, 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