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@xxxxxxxxx> wrote: > > пн, 6 янв. 2020 г. в 08:31, Boris Protopopov <boris.v.protopopov@xxxxxxxxx>: > > > > 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@xxxxxxxxx> > > 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@BUILTIN" <file_name> > > + > > ***** > > NOTES > > ***** > > -- > > 2.14.5 > > > > > -- > Best regards, > Pavel Shilovsky