4 * Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
6 * Used to alter entries of an ACL or replace an entire ACL in a
7 * security descriptor of a file system object that belongs to a
8 * share mounted using option cifsacl.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * This utility modifies various components of the security descriptor. These
25 * actions require different permissions and different SMB protocol-level flags.
26 * The user needs to make sure the share is mounted using the user credentials
27 * for the user who has appropriate permissions and privileges. The kernel
28 * CIFS client knows which flags to use based on the extended attribute name:
29 * - system.cifs_acl - set dacl only
30 * - system.cifs_ndst - set dacl and owner info
31 * - system.cifs_ntsd_full - set dacl, owner, and sacl
33 * For simplicity, the utility modifies one component of the descriptor:
34 * owner sid, group sid, DACL, or SACL. The rest of the descriptor is unchanged.
39 #endif /* HAVE_CONFIG_H */
51 #include <sys/xattr.h>
54 #include "idmap_plugin.h"
56 enum setcifsacl_actions {
68 static void *plugin_handle;
69 static bool plugin_loaded;
72 copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
76 dst->revision = src->revision;
77 size += sizeof(uint8_t);
79 dst->num_subauth = src->num_subauth;
80 size += sizeof(uint8_t);
82 for (i = 0; i < NUM_AUTHS; i++)
83 dst->authority[i] = src->authority[i];
84 size += (sizeof(uint8_t) * NUM_AUTHS);
86 for (i = 0; i < src->num_subauth; i++)
87 dst->sub_auth[i] = src->sub_auth[i];
88 size += (sizeof(uint32_t) * src->num_subauth);
94 get_cifs_sid_size(const struct cifs_sid *sid)
96 return (2 * sizeof(uint8_t) +
97 sizeof(uint8_t) * NUM_AUTHS +
98 sizeof(uint32_t) * sid->num_subauth);
102 * This function takes a pointer of the fetched (original) descriptor, and
103 * it returns the offset of the ACL in the new descriptor.
105 * If the original descriptor does not have an ACL, the corresponding offset
106 * is 0, and we need to determine where to place the ACL in the new descriptor.
107 * If SACL offset is zero, and there is DACL (dacloffset is not 0), then we will
108 * put SACL after DACL. If the DACL is not present either, we do not know if the
109 * ACLs should go before or after the owner and group SIDs (see below), and so
110 * we will use the offset right past the group SID.
111 * Similarly, if DACL offset is zero, we will use the offset the past the end
113 * @todo: need to add a command-line argument to know if this is
114 * Azure-style descriptor or a regular-style descriptor
116 static int get_aces_offset(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
117 int dacloffset, sacloffset, acesoffset;
121 sacloffset = le32toh(pntsd->sacloffset);
123 acesoffset = sacloffset + sizeof(struct cifs_ctrl_acl);
125 dacloffset = le32toh(pntsd->dacloffset);
127 struct cifs_ctrl_acl *dacl_ptr =
128 (struct cifs_ctrl_acl *)((char *)pntsd +
130 acesoffset = dacloffset +
131 le16toh(dacl_ptr->size) +
132 sizeof(struct cifs_ctrl_acl);
134 int gsidoffset = le32toh(pntsd->gsidoffset);
135 struct cifs_sid *group_sid_ptr =
136 (struct cifs_sid *)((char *)pntsd +
138 int gsidsize = get_cifs_sid_size(group_sid_ptr);
139 acesoffset = gsidoffset + gsidsize +
140 sizeof(struct cifs_ctrl_acl);
146 dacloffset = le32toh(pntsd->dacloffset);
148 acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
150 int gsidoffset = le32toh(pntsd->gsidoffset);
151 struct cifs_sid *group_sid_ptr =
152 (struct cifs_sid *)((char *)pntsd +
154 int gsidsize = get_cifs_sid_size(group_sid_ptr);
155 acesoffset = gsidoffset + gsidsize +
156 sizeof(struct cifs_ctrl_acl);
163 int get_aces_size(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
165 struct cifs_ctrl_acl *acl_ptr;
169 acloffset = le32toh(pntsd->sacloffset);
173 acloffset = le32toh(pntsd->dacloffset);
176 acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + acloffset);
177 size = le16toh(acl_ptr->size);
184 uint16_t get_acl_revision(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
185 struct cifs_ctrl_acl *acl_ptr;
189 acloffset = le32toh(pntsd->sacloffset);
191 acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd +
193 return acl_ptr->revision;
195 /* intentional fall through */
198 acloffset = le32toh(pntsd->dacloffset);
200 acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd +
202 return acl_ptr->revision;
204 return DEFAULT_ACL_REVISION;
211 * The actual changes to the ACL specified in ace_kind are performed by the
212 * caller of this function; this function copies/backfills the remaining
213 * relevant compoenents of the security descriptor that remain unchanged.
216 copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
217 int numaces, int acessize, ace_kinds ace_kind)
219 int size, osidsoffset, gsidsoffset, acloffset, dacloffset;
221 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
222 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
223 struct cifs_ctrl_acl *nacl_ptr, *dacl_ptr;
226 /* copy security descriptor control portion */
227 osidsoffset = le32toh(pntsd->osidoffset);
228 gsidsoffset = le32toh(pntsd->gsidoffset);
230 size = sizeof(struct cifs_ntsd);
231 pnntsd->revision = pntsd->revision;
232 pnntsd->type = pntsd->type;
233 pnntsd->osidoffset = pntsd->osidoffset;
234 pnntsd->gsidoffset = pntsd->gsidoffset;
235 pnntsd->dacloffset = pntsd->dacloffset;
238 /* owner and group SIDs in the original defscriptor */
239 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
240 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
242 /* get the offset of the acl control structure to initialize */
243 acloffset = get_aces_offset(pntsd, ace_kind) - sizeof(struct cifs_ctrl_acl);
244 if (ace_kind == ACE_KIND_SACL) {
245 /* copy (unchanged) DACL if present, increment bufsize */
246 dacloffset = le32toh(pntsd->dacloffset);
248 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
249 ndacl_ptr = (char *)pnntsd + dacloffset;
250 size = sizeof(struct cifs_ctrl_acl) + le16toh(dacl_ptr->size);
251 memcpy(ndacl_ptr, (char *)dacl_ptr, size);
254 /* initialize SACL offset */
255 pnntsd->sacloffset = acloffset;
258 nacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + acloffset);
259 nacl_ptr->revision = get_acl_revision(pntsd, ace_kind);
260 size = acessize + sizeof(struct cifs_ctrl_acl);
261 nacl_ptr->size = htole16(size);
262 nacl_ptr->num_aces = htole32(numaces);
268 * some servers like Azure return the owner and group SIDs at end rather
269 * than at the beginning of the ACL so don't want to overwrite the last ACEs
271 if (acloffset <= osidsoffset) {
272 /* owners placed at end of ACL */
273 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + acloffset + size);
274 osidsoffset = acloffset + size;
275 pnntsd->osidoffset = htole32(osidsoffset);
276 size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
278 /* put group SID after owner SID */
279 ngroup_sid_ptr = (struct cifs_sid *)((char *)nowner_sid_ptr + size);
280 gsidsoffset = osidsoffset + size;
281 pnntsd->gsidoffset = htole32(gsidsoffset);
284 * Most servers put the owner information at the beginning,
287 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
288 size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
290 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
294 size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
301 * This function does not need to set the SACL-related fields, and this works
302 * fine because the code path calling this function picks the 'system.cifs_ntsd'
303 * attribute name. This name tells Linux CIFS client that SACL is not modified.
306 copy_sec_desc_with_sid(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
307 struct cifs_sid *sid, int maction)
310 int osidoffset, gsidoffset, dacloffset;
311 int nosidoffset, ngsidoffset, ndacloffset, nsidssize;
313 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
314 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
315 struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
317 /* copy security descriptor control portion */
318 osidoffset = le32toh(pntsd->osidoffset);
319 gsidoffset = le32toh(pntsd->gsidoffset);
320 dacloffset = le32toh(pntsd->dacloffset);
322 * the size of the owner or group sid might be different from the old
323 * one, so the group sid offest might change, and if the owner is
324 * positioned before the DACL, the dacl offset might change as well;
325 * note however, that the owner sid offset does not change
327 nosidoffset = osidoffset;
328 size = sizeof(struct cifs_ntsd);
329 pnntsd->revision = pntsd->revision;
330 pnntsd->type = pntsd->type;
331 pnntsd->osidoffset = pntsd->osidoffset;
334 /* set the pointers for source sids */
335 if (maction == ActSetOwner) {
337 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidoffset);
339 if (maction == ActSetGroup) {
340 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidoffset);
345 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
346 daclsize = le16toh(dacl_ptr->size) + sizeof(struct cifs_ctrl_acl);
353 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + nosidoffset);
354 size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
359 ngsidoffset = nosidoffset + size;
360 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + ngsidoffset);
361 pnntsd->gsidoffset = htole32(ngsidoffset);
362 size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
366 /* position the dacl control info as in the fetched descriptor */
368 if (dacloffset <= osidoffset)
369 ndacloffset = dacloffset;
371 ndacloffset = nosidoffset + nsidssize;
372 ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + ndacloffset);
373 pnntsd->dacloffset = htole32(ndacloffset);
375 /* the DACL control fields do not change */
376 ndacl_ptr->revision = dacl_ptr->revision;
377 ndacl_ptr->size = dacl_ptr->size;
378 ndacl_ptr->num_aces = dacl_ptr->num_aces;
380 pnntsd->dacloffset = 0;
383 * add DACL size (control portion and the array of aces) to the
392 copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
394 dace->type = sace->type;
395 dace->flags = sace->flags;
396 dace->access_req = sace->access_req;
398 copy_cifs_sid(&dace->sid, &sace->sid);
400 dace->size = sace->size;
402 return le16toh(dace->size);
406 compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
410 if (compflags & COMPSID) {
411 if (dace->sid.revision != sace->sid.revision)
413 if (dace->sid.num_subauth != sace->sid.num_subauth)
415 for (i = 0; i < NUM_AUTHS; i++) {
416 if (dace->sid.authority[i] != sace->sid.authority[i])
419 for (i = 0; i < sace->sid.num_subauth; i++) {
420 if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
425 if (compflags & COMPTYPE) {
426 if (dace->type != sace->type)
430 if (compflags & COMPFLAG) {
431 if (dace->flags != sace->flags)
435 if (compflags & COMPMASK) {
436 if (dace->access_req != sace->access_req)
444 * This is somewhat suboptimal, but to keep the code simple, we will still
445 * allocate the ACL control headers for DACL and SACL even thought there is
446 * no corresponding ACL (dacloffset = 0 or sacloffset = 0).
447 * When seetting DACL, we allocate sufficient space for the descriptor control
448 * structure, owner and group sids, and the DACL (ACL control structure and
450 * When setting SACL, we allocate sufficient space to copy the above components
451 * plus the SACL to be set (ACL controla and aces).
454 alloc_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
455 int aces, size_t *acesoffset, ace_kinds ace_kind)
457 unsigned int size, acessize, bufsize;
461 size = sizeof(struct cifs_ntsd) +
462 2 * sizeof(struct cifs_sid) +
463 sizeof(struct cifs_ctrl_acl) +
464 get_aces_size(pntsd, ACE_KIND_DACL) +
465 sizeof(struct cifs_ctrl_acl);
469 size = sizeof(struct cifs_ntsd) +
470 2 * sizeof(struct cifs_sid) +
471 sizeof(struct cifs_ctrl_acl);
475 *acesoffset = get_aces_offset(pntsd, ace_kind);
476 acessize = aces * sizeof(struct cifs_ace);
477 bufsize = size + acessize;
478 *npntsd = calloc(1, bufsize);
480 fprintf(stderr, "%s: Memory allocation failure", __func__);
487 static struct cifs_ace **
488 build_reorder_aces(struct cifs_ace **facesptr, int numfaces)
490 struct cifs_ace *pace, **allowedacesptr, **deniedacesptr,
491 **allowedinhacesptr, **deniedinhacesptr, **reorderacesptr;
492 int i, numallowedaces, numdeniedaces,
493 numallowedinhaces, numdeniedinhaces, numreorderaces;
495 allowedacesptr = calloc(numfaces, sizeof(struct cifs_aces *));
496 deniedacesptr = calloc(numfaces, sizeof(struct cifs_aces *));
497 allowedinhacesptr = calloc(numfaces, sizeof(struct cifs_aces *));
498 deniedinhacesptr = calloc(numfaces, sizeof(struct cifs_aces *));
499 reorderacesptr = calloc(numfaces, sizeof(struct cifs_aces *));
503 numallowedinhaces = 0;
504 numdeniedinhaces = 0;
507 for (i = 0; i < numfaces; i++) {
509 if ((pace->type == ACCESS_DENIED) || (pace->type == ACCESS_DENIED_OBJECT)) {
510 if (!(pace->flags & INHERITED_ACE_FLAG)) {
511 deniedacesptr[numdeniedaces] = malloc(sizeof(struct cifs_ace));
512 memcpy(deniedacesptr[numdeniedaces], pace, sizeof(struct cifs_ace));
515 deniedinhacesptr[numdeniedinhaces] = malloc(sizeof(struct cifs_ace));
516 memcpy(deniedinhacesptr[numdeniedinhaces], pace, sizeof(struct cifs_ace));
519 } else if ((pace->type == ACCESS_ALLOWED) || (pace->type == ACCESS_ALLOWED_OBJECT)) {
520 if (!(pace->flags & INHERITED_ACE_FLAG)) {
521 allowedacesptr[numallowedaces] = malloc(sizeof(struct cifs_ace));
522 memcpy(allowedacesptr[numallowedaces], pace, sizeof(struct cifs_ace));
525 allowedinhacesptr[numallowedinhaces] = malloc(sizeof(struct cifs_ace));
526 memcpy(allowedinhacesptr[numallowedinhaces], pace, sizeof(struct cifs_ace));
532 for (i = 0; i < numdeniedaces; i++) {
533 reorderacesptr[numreorderaces] = malloc(sizeof(struct cifs_ace));
534 memcpy(reorderacesptr[numreorderaces], deniedacesptr[i], sizeof(struct cifs_ace));
536 free(deniedacesptr[i]);
539 for (i = 0; i < numallowedaces; i++) {
540 reorderacesptr[numreorderaces] = malloc(sizeof(struct cifs_ace));
541 memcpy(reorderacesptr[numreorderaces], allowedacesptr[i], sizeof(struct cifs_ace));
543 free(allowedacesptr[i]);
546 for (i = 0; i < numdeniedinhaces; i++) {
547 reorderacesptr[numreorderaces] = malloc(sizeof(struct cifs_ace));
548 memcpy(reorderacesptr[numreorderaces], deniedinhacesptr[i], sizeof(struct cifs_ace));
550 free(deniedinhacesptr[i]);
553 for (i = 0; i < numallowedinhaces; i++) {
554 reorderacesptr[numreorderaces] = malloc(sizeof(struct cifs_ace));
555 memcpy(reorderacesptr[numreorderaces], allowedinhacesptr[i], sizeof(struct cifs_ace));
557 free(allowedinhacesptr[i]);
561 free(allowedacesptr);
562 free(deniedinhacesptr);
563 free(allowedinhacesptr);
565 return reorderacesptr;
569 ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
570 struct cifs_ace **cacesptr, int numcaces, ace_kinds ace_kind)
572 int i, rc, size = 0, acessize = 0;
576 rc = alloc_sec_desc(pntsd, npntsd, numcaces, &acesoffset, ace_kind);
580 acesptr = (char *)*npntsd + acesoffset;
581 for (i = 0; i < numcaces; ++i) {
582 size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
587 *bufsize = copy_sec_desc(pntsd, *npntsd, numcaces, acessize, ace_kind);
593 ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
594 struct cifs_ace **facesptr, int numfaces,
595 struct cifs_ace **cacesptr, int numcaces,
598 int i, rc, numaces, size, acessize = 0;
602 numaces = numfaces + numcaces;
603 rc = alloc_sec_desc(pntsd, npntsd, numaces, &acesoffset, ace_kind);
607 acesptr = (char *)*npntsd + acesoffset;
608 for (i = 0; i < numfaces; ++i) {
609 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
613 for (i = 0; i < numcaces; ++i) {
614 size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
619 *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize, ace_kind);
625 ace_add_reorder(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
626 struct cifs_ace **facesptr, int numfaces,
627 struct cifs_ace **cacesptr, int numcaces,
630 struct cifs_ace **reorderacesptr, **totalacesptr;
633 numaces = numfaces + numcaces;
634 totalacesptr = calloc(numaces, sizeof(struct cifs_aces *));
636 for (i = 0; i < numfaces; i++) {
637 totalacesptr[i] = facesptr[i];
640 for (i = numfaces; i < numaces; i++) {
641 totalacesptr[i] = cacesptr[i - numfaces];
644 reorderacesptr = build_reorder_aces(totalacesptr, numaces);
645 rc = ace_add(pntsd, npntsd, bufsize, reorderacesptr,
646 numaces, cacesptr, 0, ace_kind);
649 free(reorderacesptr);
654 ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
655 struct cifs_ace **facesptr, int numfaces,
656 struct cifs_ace **cacesptr, int numcaces,
659 int i, j, rc, size, acessize = 0;
664 fprintf(stderr, "%s: No entries to modify", __func__);
668 rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset, ace_kind);
672 for (j = 0; j < numcaces; ++j) {
673 for (i = 0; i < numfaces; ++i) {
674 if (compare_aces(facesptr[i], cacesptr[j],
675 COMPSID | COMPTYPE)) {
676 copy_ace(facesptr[i], cacesptr[j]);
682 acesptr = (char *)*npntsd + acesoffset;
683 for (i = 0; i < numfaces; ++i) {
684 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
689 *bufsize = copy_sec_desc(pntsd, *npntsd, numfaces, acessize, ace_kind);
695 ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
696 struct cifs_ace **facesptr, int numfaces,
697 struct cifs_ace **cacesptr, int numcaces,
700 int i, j, numaces = 0, rc, size, acessize = 0;
705 fprintf(stderr, "%s: No entries to delete\n", __func__);
709 if (numfaces < numcaces) {
710 fprintf(stderr, "%s: Invalid entries to delete\n", __func__);
714 rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset, ace_kind);
718 acesptr = (char *)*npntsd + acesoffset;
719 for (i = 0; i < numfaces; ++i) {
720 for (j = 0; j < numcaces; ++j) {
721 if (compare_aces(facesptr[i], cacesptr[j], COMPALL))
725 size = copy_ace((struct cifs_ace *)acesptr,
733 if (numaces == numfaces) {
734 fprintf(stderr, "%s: Nothing to delete\n", __func__);
738 *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize, ace_kind);
744 get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
745 struct cifs_ctrl_acl **aclptr, ace_kinds ace_kind)
749 struct cifs_ctrl_acl *laclptr;
750 char *end_of_acl = ((char *)pntsd) + acl_len;
754 acloffset = le32toh(pntsd->sacloffset);
758 acloffset = le32toh(pntsd->dacloffset);
765 laclptr = (struct cifs_ctrl_acl *)((char *)pntsd + acloffset);
767 /* validate that we do not go past end of acl */
768 if (end_of_acl >= (char *)laclptr + le16toh(laclptr->size)) {
769 numfaces = le32toh(laclptr->num_aces);
776 static struct cifs_ace **
777 build_fetched_aces(char *aclptr, int numfaces)
781 struct cifs_ace *pace, **facesptr;
783 facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
785 fprintf(stderr, "%s: Error %d allocating ACE array",
791 acl_size = sizeof(struct cifs_ctrl_acl);
792 for (i = 0; i < numfaces; ++i) {
793 facesptr[i] = malloc(sizeof(struct cifs_ace));
795 goto build_fetched_aces_err;
796 pace = (struct cifs_ace *) (acl_base + acl_size);
797 memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
798 acl_base = (char *)pace;
799 acl_size = le16toh(pace->size);
803 build_fetched_aces_err:
804 fprintf(stderr, "%s: Invalid fetched ace\n", __func__);
805 for (i = 0; i < numfaces; ++i)
812 verify_ace_type(char *typestr, uint8_t *typeval, ace_kinds ace_kind)
816 uint8_t ace_type_mask;
820 ace_type_mask = SACL_VTYPES;
824 ace_type_mask = DACL_VTYPES;
828 if (strstr(typestr, "0x")) { /* hex type value */
829 *typeval = strtol(typestr, &invaltype, 16);
830 if (!strlen(invaltype)) {
831 /* the type must be a single bit from the bit mask */
832 if (*typeval != (*typeval & ace_type_mask)) {
833 fprintf(stderr, "%s: Invalid type: %s\n",
841 len = strlen(typestr);
844 for (i = 0; i < len; ++i)
845 *(typestr + i) = toupper(*(typestr + i));
846 if (!strcmp(typestr, "AUDIT"))
847 *typeval = SYSTEM_AUDIT;
848 else if (!strcmp(typestr, "AUDIT_OBJECT"))
849 *typeval = SYSTEM_AUDIT_OBJECT;
850 else if (!strcmp(typestr, "AUDIT_CALLBACK"))
851 *typeval = SYSTEM_AUDIT_CALLBACK;
852 else if (!strcmp(typestr, "AUDIT_CALLBACK_OBJECT"))
853 *typeval = SYSTEM_AUDIT_CALLBACK_OBJECT;
854 else if (!strcmp(typestr, "MANDATODY_LABEL"))
855 *typeval = SYSTEM_MANDATORY_LABEL;
856 else if (!strcmp(typestr, "RESOURCE_ATTRIBUTE"))
857 *typeval = SYSTEM_RESOURCE_ATTRIBUTE;
858 else if (!strcmp(typestr, "SCOPED_POLICY_ID"))
859 *typeval = SYSTEM_SCOPED_POLICY_ID;
861 fprintf(stderr, "%s: Invalid type: %s\n", __func__,
868 for (i = 0; i < len; ++i)
869 *(typestr + i) = toupper(*(typestr + i));
870 if (!strcmp(typestr, "ALLOWED"))
871 *typeval = ACCESS_ALLOWED;
872 else if (!strcmp(typestr, "DENIED"))
873 *typeval = ACCESS_DENIED;
874 else if (!strcmp(typestr, "ALLOWED_OBJECT"))
875 *typeval = ACCESS_ALLOWED_OBJECT;
876 else if (!strcmp(typestr, "DENIED_OBJECT"))
877 *typeval = ACCESS_DENIED_OBJECT;
879 fprintf(stderr, "%s: Invalid type: %s\n", __func__, typestr);
889 ace_flag_value(char *flagstr, ace_kinds ace_kind)
891 uint8_t flagval = 0x0;
894 iflag = strtok(flagstr, "|"); /* everything before | */
898 if (!strcmp(iflag, "SA"))
899 flagval |= SUCCESSFUL_ACCESS;
900 else if (!strcmp(iflag, "FA"))
901 flagval |= FAILED_ACCESS;
903 return 0x0; /* Invalid flag */
904 iflag = strtok(NULL, "|"); /* everything before | */
910 if (!strcmp(iflag, "OI"))
911 flagval |= OBJECT_INHERIT_FLAG;
912 else if (!strcmp(iflag, "CI"))
913 flagval |= CONTAINER_INHERIT_FLAG;
914 else if (!strcmp(iflag, "NP"))
915 flagval |= NO_PROPAGATE_INHERIT_FLAG;
916 else if (!strcmp(iflag, "IO"))
917 flagval |= INHERIT_ONLY_FLAG;
918 else if (!strcmp(iflag, "I"))
919 flagval |= INHERITED_ACE_FLAG;
921 return 0x0; /* Invalid flag */
922 iflag = strtok(NULL, "|"); /* everything before | */
931 verify_ace_flags(char *flagstr, uint8_t *flagval, ace_kinds ace_kind)
934 uint8_t ace_flag_mask = 0;
936 if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
939 if (strstr(flagstr, "0x")) { /* hex flag value */
940 *flagval = strtol(flagstr, &invalflag, 16);
941 if (strlen(invalflag)) {
942 fprintf(stderr, "%s: Invalid flags: %s\n", __func__,
947 *flagval = ace_flag_value(flagstr, ace_kind);
951 ace_flag_mask = SACL_VFLAGS;
955 ace_flag_mask = DACL_VFLAGS;
958 if (!*flagval || (*flagval & ~ace_flag_mask)) {
959 fprintf(stderr, "%s: Invalid flag %s and value: 0x%x\n",
960 __func__, flagstr, *flagval);
968 ace_mask_value(char *mask)
970 uint32_t maskval = 0;
973 if (!strcmp(mask, "FULL"))
975 if (!strcmp(mask, "CHANGE"))
977 if (!strcmp(mask, "READ"))
979 if (!strcmp(mask, "RWXDPO"))
980 return ALL_ACCESS_BITS;
982 while((cur = *mask++)) {
997 maskval |= WRITE_DAC;
1000 maskval |= WRITE_OWNER;
1010 verify_ace_mask(char *maskstr, uint32_t *maskval)
1016 val = strtoul(maskstr, &ep, 0);
1017 if (errno == 0 && *ep == '\0')
1018 *maskval = htole32((uint32_t)val);
1020 *maskval = htole32(ace_mask_value(maskstr));
1023 fprintf(stderr, "%s: Invalid mask %s (value 0x%x)\n", __func__,
1031 #define AUTHORITY_MASK (~(0xffffffffffffULL))
1034 raw_str_to_sid(const char *str, struct cifs_sid *csid)
1038 unsigned long long x;
1040 /* Sanity check for either "S-" or "s-" */
1041 if ((str[0] != 'S' && str[0] != 's') || (str[1]!='-')) {
1042 plugin_errmsg = "SID string does not start with \"S-\"";
1046 /* Get the SID revision number */
1048 x = strtoull(p, &q, 10);
1049 if (x == 0 || x > UCHAR_MAX || !q || *q != '-') {
1050 plugin_errmsg = "Invalid SID revision number";
1053 csid->revision = (uint8_t)x;
1056 * Next the Identifier Authority. This is stored in big-endian in a
1057 * 6 byte array. If the authority value is > UINT_MAX, then it should
1058 * be expressed as a hex value.
1061 x = strtoull(p, &q, 0);
1062 if ((x & AUTHORITY_MASK) || !q || *q !='-') {
1063 plugin_errmsg = "Invalid SID authority";
1066 csid->authority[5] = (x & 0x0000000000ffULL);
1067 csid->authority[4] = (x & 0x00000000ff00ULL) >> 8;
1068 csid->authority[3] = (x & 0x000000ff0000ULL) >> 16;
1069 csid->authority[2] = (x & 0x0000ff000000ULL) >> 24;
1070 csid->authority[1] = (x & 0x00ff00000000ULL) >> 32;
1071 csid->authority[0] = (x & 0xff0000000000ULL) >> 40;
1073 /* now read the the subauthorities and store as __le32 vals */
1075 csid->num_subauth = 0;
1076 while (csid->num_subauth < SID_MAX_SUB_AUTHORITIES) {
1077 x = strtoul(p, &q, 10);
1081 plugin_errmsg = "Invalid sub authority value";
1084 csid->sub_auth[csid->num_subauth++] = htole32((uint32_t)x);
1091 /* IF we ended early, then the SID could not be converted */
1092 if (q && *q != '\0') {
1093 plugin_errmsg = "Invalid sub authority value";
1101 setcifsacl_str_to_sid(const char *str, struct cifs_sid *sid)
1104 return str_to_sid(plugin_handle, str, sid);
1105 return raw_str_to_sid(str, sid);
1108 static struct cifs_ace **
1109 build_cmdline_aces(char **arrptr, int numcaces, ace_kinds ace_kind)
1112 char *acesid, *acetype, *aceflag, *acemask;
1113 struct cifs_ace **cacesptr;
1115 cacesptr = calloc(numcaces, sizeof(struct cifs_aces *));
1117 fprintf(stderr, "%s: Error %d allocating ACE array", __func__,
1122 for (i = 0; i < numcaces; ++i) {
1123 acesid = strtok(arrptr[i], ":");
1124 acetype = strtok(NULL, "/");
1125 aceflag = strtok(NULL, "/");
1126 acemask = strtok(NULL, "/");
1128 if (!acesid || !acetype || !aceflag || !acemask) {
1129 fprintf(stderr, "%s: Incomplete ACE: %s\n", __func__,
1131 goto build_cmdline_aces_ret;
1134 cacesptr[i] = calloc(1, sizeof(struct cifs_ace));
1136 fprintf(stderr, "%s: ACE alloc error %d\n", __func__,
1138 goto build_cmdline_aces_ret;
1141 if (setcifsacl_str_to_sid(acesid, &cacesptr[i]->sid)) {
1142 fprintf(stderr, "%s: Invalid SID (%s): %s\n", __func__,
1143 arrptr[i], plugin_errmsg);
1144 goto build_cmdline_aces_ret;
1147 if (verify_ace_type(acetype, &cacesptr[i]->type, ace_kind)) {
1148 fprintf(stderr, "%s: Invalid ACE type: %s\n",
1149 __func__, arrptr[i]);
1150 goto build_cmdline_aces_ret;
1153 if (verify_ace_flags(aceflag, &cacesptr[i]->flags, ace_kind)) {
1154 fprintf(stderr, "%s: Invalid ACE flag: %s\n",
1155 __func__, arrptr[i]);
1156 goto build_cmdline_aces_ret;
1159 if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
1160 fprintf(stderr, "%s: Invalid ACE mask: %s\n",
1161 __func__, arrptr[i]);
1162 goto build_cmdline_aces_ret;
1165 cacesptr[i]->size = htole16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
1166 cacesptr[i]->sid.num_subauth * 4);
1170 build_cmdline_aces_ret:
1171 for (i = 0; i < numcaces; ++i)
1178 parse_cmdline_aces(char *acelist, int numcaces)
1181 char *acestr, *vacestr, **arrptr = NULL;
1183 arrptr = (char **)malloc(numcaces * sizeof(char *));
1185 fprintf(stderr, "%s: Unable to allocate char array\n",
1190 while (i < numcaces) {
1191 acestr = strtok(acelist, ","); /* everything before , */
1193 goto parse_cmdline_aces_err;
1195 vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
1197 goto parse_cmdline_aces_err;
1198 vacestr += 4; /* skip past "ACL:" */
1200 arrptr[i] = vacestr;
1207 parse_cmdline_aces_err:
1208 fprintf(stderr, "%s: Error parsing ACEs\n", __func__);
1213 /* How many aces were provided on the command-line? Count the commas. */
1215 get_numcaces(const char *aces)
1217 unsigned int num = 1;
1218 const char *current;
1221 while((current = strchr(current, ','))) {
1230 setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
1231 ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
1232 struct cifs_ace **cacesptr, int numcaces,
1233 enum setcifsacl_actions maction, ace_kinds ace_kind)
1239 rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
1240 numfaces, cacesptr, numcaces, ace_kind);
1243 rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
1244 numfaces, cacesptr, numcaces, ace_kind);
1247 rc = ace_add(pntsd, npntsd, bufsize, facesptr,
1248 numfaces, cacesptr, numcaces, ace_kind);
1251 rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces,
1255 rc = ace_add_reorder(pntsd, npntsd, bufsize, facesptr,
1256 numfaces, cacesptr, numcaces, ace_kind);
1259 fprintf(stderr, "%s: Invalid action: %d\n", __func__, maction);
1267 setcifsacl_usage(const char *prog)
1270 "%s: Alter components of CIFS/NTFS security descriptor of a file object\n",
1272 fprintf(stderr, "Usage: %s option [<list_of_ACEs>|<SID>] <file_name>\n",
1274 fprintf(stderr, "Valid options:\n");
1275 fprintf(stderr, "\t-v Version of the program\n");
1276 fprintf(stderr, "\t-U Used in combination with -a, -D, -M, -S in order to ");
1277 fprintf(stderr, "\n\t apply the actions to SALC (aUdit ACL); if not specified, ");
1278 fprintf(stderr, "\n\t the actions apply to DACL\n");
1279 fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
1281 "\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
1282 fprintf(stderr, "\n");
1283 fprintf(stderr, "\t-A Add ACE(s) and reorder, separated by a comma, to an ACL\n");
1285 "\tsetcifsacl -A \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
1286 fprintf(stderr, "\n");
1288 "\t-D Delete ACE(s), separated by a comma, from an ACL\n");
1290 "\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
1291 fprintf(stderr, "\n");
1293 "\t-M Modify ACE(s), separated by a comma, in an ACL\n");
1295 "\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
1297 "\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
1299 "\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
1301 "\n\t-o Set owner using specified SID (name or raw format)\n");
1303 "\tsetcifsacl -o \"Administrator\" <file_name>\n");
1305 "\n\t-g Set group using specified SID (name or raw format)\n");
1307 "\tsetcifsacl -g \"Administrators\" <file_name>\n");
1308 fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
1312 main(const int argc, char *const argv[])
1314 int i, rc, c, numcaces = 0, numfaces = 0;
1315 enum setcifsacl_actions maction = ActUnknown;
1316 ssize_t attrlen, bufsize = BUFSIZE;
1317 char *ace_list = NULL, *filename = NULL, *attrval = NULL,
1318 **arrptr = NULL, *sid_str = NULL;
1319 struct cifs_ctrl_acl *aclptr = NULL;
1320 struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
1321 struct cifs_ntsd *ntsdptr = NULL;
1322 struct cifs_sid sid;
1323 char *attrname = ATTRNAME_ACL;
1324 ace_kinds ace_kind = ACE_KIND_DACL;
1326 while ((c = getopt(argc, argv, "hvD:M:a:A:S:o:g:U")) != -1) {
1329 ace_kind = ACE_KIND_SACL;
1330 attrname = ATTRNAME_NTSD_FULL;
1333 maction = ActDelete;
1337 maction = ActModify;
1345 maction = ActAddReorder;
1349 maction = ActSetAcl;
1353 maction = ActSetOwner;
1355 attrname = ATTRNAME_NTSD;
1358 maction = ActSetGroup;
1360 attrname = ATTRNAME_NTSD;
1363 setcifsacl_usage(basename(argv[0]));
1366 printf("Version: %s\n", VERSION);
1369 setcifsacl_usage(basename(argv[0]));
1374 /* We expect 1 required and one optional argument in addition to the option */
1375 if (argc < 4 || argc > 5) {
1376 setcifsacl_usage(basename(argv[0]));
1379 filename = argv[argc-1];
1381 if (!ace_list && maction != ActSetOwner && maction != ActSetGroup) {
1382 fprintf(stderr, "%s: No valid ACEs specified\n", __func__);
1386 if (!sid_str && (maction == ActSetOwner || maction == ActSetGroup)) {
1387 fprintf(stderr, "%s: No valid SIDs specified\n", __func__);
1391 if (init_plugin(&plugin_handle)) {
1392 fprintf(stderr, "WARNING: unable to initialize idmapping "
1393 "plugin. Only \"raw\" SID strings will be "
1394 "accepted: %s\n", plugin_errmsg);
1395 plugin_loaded = false;
1397 plugin_loaded = true;
1400 if (maction == ActSetOwner || maction == ActSetGroup) {
1401 if (ace_kind == ACE_KIND_SACL) {
1402 fprintf(stderr, "WARNING: disregarding -U when setting"
1404 ace_kind = ACE_KIND_DACL;
1407 if (setcifsacl_str_to_sid(sid_str, &sid)) {
1408 fprintf(stderr, "%s: failed to parce \'%s\' as SID\n",
1410 goto setcifsacl_numcaces_ret;
1413 numcaces = get_numcaces(ace_list);
1415 arrptr = parse_cmdline_aces(ace_list, numcaces);
1417 goto setcifsacl_numcaces_ret;
1419 cacesptr = build_cmdline_aces(arrptr, numcaces, ace_kind);
1421 goto setcifsacl_cmdlineparse_ret;
1424 if (bufsize >= XATTR_SIZE_MAX) {
1425 fprintf(stderr, "%s: Buffer size %zd exceeds max size of %d\n",
1426 __func__, bufsize, XATTR_SIZE_MAX);
1427 goto setcifsacl_cmdlineverify_ret;
1430 attrval = malloc(bufsize * sizeof(char));
1432 fprintf(stderr, "error allocating memory for attribute value "
1434 goto setcifsacl_cmdlineverify_ret;
1437 attrlen = getxattr(filename, attrname, attrval, bufsize);
1438 if (attrlen == -1) {
1439 if (errno == ERANGE) {
1444 fprintf(stderr, "getxattr error: %d\n", errno);
1445 goto setcifsacl_getx_ret;
1449 if (maction == ActSetOwner || maction == ActSetGroup) {
1450 struct cifs_ntsd *pfntsd = (struct cifs_ntsd *)attrval;
1451 int dacloffset = le32toh(pfntsd->dacloffset);
1452 struct cifs_ctrl_acl *daclinfo;
1453 int numaces, acessize;
1454 size_t faceoffset, naceoffset;
1455 char *faceptr, *naceptr;
1457 * dacloffset of 0 means "no DACL - all access for everyone"
1458 * if dacloffset is not 0, it is still possible that DACL is
1459 * empty - numaces is zero - "no access for anyone"
1462 daclinfo = (struct cifs_ctrl_acl *)(attrval + dacloffset);
1463 numaces = le16toh(daclinfo->num_aces);
1464 acessize = le32toh(daclinfo->size);
1471 * this allocates large enough buffer for max sid size and the
1472 * dacl info from the fetched security descriptor
1474 rc = alloc_sec_desc(pfntsd, &ntsdptr, numaces, &faceoffset,
1477 goto setcifsacl_numcaces_ret;
1480 * copy the control structures from the fetched descriptor, the
1481 * sid specified by the user, and adjust the offsets/move dacl
1482 * control structure if needed
1484 bufsize = copy_sec_desc_with_sid(pfntsd, ntsdptr, &sid,
1487 /* copy DACL aces verbatim as they have not changed */
1489 faceptr = attrval + faceoffset;
1490 naceoffset = le32toh(ntsdptr->dacloffset) +
1491 sizeof(struct cifs_ctrl_acl);
1492 naceptr = (char *)ntsdptr + naceoffset;
1493 memcpy(naceptr, faceptr, acessize);
1498 numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen,
1500 if (!numfaces && (maction != ActAdd && maction != ActAddReorder)) {
1501 /* if we are not adding aces */
1502 fprintf(stderr, "%s: Empty DACL\n", __func__);
1503 goto setcifsacl_facenum_ret;
1506 facesptr = build_fetched_aces((char *)aclptr, numfaces);
1508 goto setcifsacl_facenum_ret;
1510 rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr,
1511 &bufsize, facesptr, numfaces, cacesptr,
1512 numcaces, maction, ace_kind);
1514 goto setcifsacl_action_ret;
1517 attrlen = setxattr(filename, attrname, ntsdptr, bufsize, 0);
1518 if (attrlen == -1) {
1519 fprintf(stderr, "%s: setxattr error: %s\n", __func__,
1521 goto setcifsacl_action_ret;
1525 exit_plugin(plugin_handle);
1528 setcifsacl_action_ret:
1532 setcifsacl_facenum_ret:
1534 for (i = 0; i < numfaces; ++i)
1539 setcifsacl_getx_ret:
1543 setcifsacl_cmdlineverify_ret:
1545 for (i = 0; i < numcaces; ++i)
1550 setcifsacl_cmdlineparse_ret:
1554 setcifsacl_numcaces_ret:
1556 exit_plugin(plugin_handle);