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
25 #endif /* HAVE_CONFIG_H */
39 #include <sys/xattr.h>
42 static const char *prog = "setcifsacl";
45 copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
46 int numaces, int acessize)
50 int osidsoffset, gsidsoffset, dacloffset;
51 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
52 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
53 struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
55 /* copy security descriptor control portion */
56 osidsoffset = htole32(pntsd->osidoffset);
57 gsidsoffset = htole32(pntsd->gsidoffset);
58 dacloffset = htole32(pntsd->dacloffset);
60 pnntsd->revision = pntsd->revision;
61 pnntsd->type = pntsd->type;
62 pnntsd->osidoffset = pntsd->osidoffset;
63 pnntsd->gsidoffset = pntsd->gsidoffset;
64 pnntsd->dacloffset = pntsd->dacloffset;
66 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
67 ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
69 ndacl_ptr->revision = dacl_ptr->revision;
70 ndacl_ptr->size = htole16(acessize + sizeof(struct cifs_ctrl_acl));
71 ndacl_ptr->num_aces = htole32(numaces);
74 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
75 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
77 nowner_sid_ptr->revision = owner_sid_ptr->revision;
78 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
79 for (i = 0; i < NUM_AUTHS; i++)
80 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
81 for (i = 0; i < owner_sid_ptr->num_subauth; i++)
82 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
85 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
86 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
88 ngroup_sid_ptr->revision = group_sid_ptr->revision;
89 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
90 for (i = 0; i < NUM_AUTHS; i++)
91 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
92 for (i = 0; i < group_sid_ptr->num_subauth; i++)
93 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
99 copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
103 dace->type = sace->type;
104 dace->flags = sace->flags;
105 dace->access_req = htole32(sace->access_req);
107 dace->sid.revision = sace->sid.revision;
108 dace->sid.num_subauth = sace->sid.num_subauth;
109 for (i = 0; i < NUM_AUTHS; i++)
110 dace->sid.authority[i] = sace->sid.authority[i];
111 for (i = 0; i < sace->sid.num_subauth; i++)
112 dace->sid.sub_auth[i] = sace->sid.sub_auth[i];
114 dace->size = htole16(sace->size);
120 compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
124 if (compflags & COMPSID) {
125 if (dace->sid.revision != sace->sid.revision)
127 if (dace->sid.num_subauth != sace->sid.num_subauth)
129 for (i = 0; i < NUM_AUTHS; i++) {
130 if (dace->sid.authority[i] != sace->sid.authority[i])
133 for (i = 0; i < sace->sid.num_subauth; i++) {
134 if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
139 if (compflags & COMPTYPE) {
140 if (dace->type != sace->type)
144 if (compflags & COMPFLAG) {
145 if (dace->flags != sace->flags)
149 if (compflags & COMPMASK) {
150 if (dace->access_req != htole32(sace->access_req))
158 get_sec_desc_size(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
159 int aces, ssize_t *bufsize, size_t *acesoffset)
161 unsigned int size, acessize, dacloffset;
163 size = sizeof(struct cifs_ntsd) +
164 2 * sizeof(struct cifs_sid) +
165 sizeof(struct cifs_ctrl_acl);
167 dacloffset = le32toh(pntsd->dacloffset);
169 *acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
170 acessize = aces * sizeof(struct cifs_ace);
171 *bufsize = size + acessize;
173 *npntsd = malloc(*bufsize);
175 printf("%s: Memory allocation failure", __func__);
183 ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
184 struct cifs_ace **cacesptr, int numcaces)
186 int i, rc, acessize = 0;
190 rc = get_sec_desc_size(pntsd, npntsd, numcaces, bufsize, &acesoffset);
194 acesptr = (char *)*npntsd + acesoffset;
195 for (i = 0; i < numcaces; ++i) {
196 acessize += copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
197 acesptr += sizeof(struct cifs_ace);
199 copy_sec_desc(pntsd, *npntsd, numcaces, acessize);
200 acesptr = (char *)*npntsd + acesoffset;
207 ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
208 struct cifs_ace **facesptr, int numfaces,
209 struct cifs_ace **cacesptr, int numcaces)
211 int i, rc, numaces, size, acessize = 0;
215 numaces = numfaces + numcaces;
216 rc = get_sec_desc_size(pntsd, npntsd, numaces, bufsize, &acesoffset);
220 acesptr = (char *)*npntsd + acesoffset;
221 for (i = 0; i < numfaces; ++i) {
222 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
226 for (i = 0; i < numcaces; ++i) {
227 size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
231 copy_sec_desc(pntsd, *npntsd, numaces, acessize);
237 ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
238 struct cifs_ace **facesptr, int numfaces,
239 struct cifs_ace **cacesptr, int numcaces)
241 int i, j, rc, size, acessize = 0;
246 printf("%s: No entries to modify", __func__);
250 rc = get_sec_desc_size(pntsd, npntsd, numfaces, bufsize, &acesoffset);
254 for (j = 0; j < numcaces; ++j) {
255 for (i = 0; i < numfaces; ++i) {
256 if (compare_aces(facesptr[i], cacesptr[j],
257 COMPSID | COMPTYPE)) {
258 copy_ace(facesptr[i], cacesptr[j]);
264 acesptr = (char *)*npntsd + acesoffset;
265 for (i = 0; i < numfaces; ++i) {
266 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
271 copy_sec_desc(pntsd, *npntsd, numfaces, acessize);
277 ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
278 struct cifs_ace **facesptr, int numfaces,
279 struct cifs_ace **cacesptr, int numcaces)
281 int i, j, numaces = 0, rc, size, acessize = 0;
286 printf("%s: No entries to delete\n", __func__);
290 if (numfaces < numcaces) {
291 printf("%s: Invalid entries to delete\n", __func__);
295 rc = get_sec_desc_size(pntsd, npntsd, numfaces, bufsize, &acesoffset);
299 acesptr = (char *)*npntsd + acesoffset;
300 for (i = 0; i < numfaces; ++i) {
301 for (j = 0; j < numcaces; ++j) {
302 if (compare_aces(facesptr[i], cacesptr[j], COMPALL))
306 size = copy_ace((struct cifs_ace *)acesptr,
314 if (numaces == numfaces) {
315 printf("%s: Nothing to delete\n", __func__);
318 copy_sec_desc(pntsd, *npntsd, numaces, acessize);
324 get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
325 struct cifs_ctrl_acl **daclptr)
329 struct cifs_ctrl_acl *ldaclptr;
330 char *end_of_acl = ((char *)pntsd) + acl_len;
335 dacloffset = le32toh(pntsd->dacloffset);
339 ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
340 /* validate that we do not go past end of acl */
341 if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
342 numfaces = le32toh(ldaclptr->num_aces);
350 static struct cifs_ace **
351 build_fetched_aces(char *daclptr, int numfaces)
353 int i, j, rc = 0, acl_size;
355 struct cifs_ace *pace, **facesptr;
357 facesptr = (struct cifs_ace **)malloc(numfaces *
358 sizeof(struct cifs_aces *));
360 printf("%s: Error %d allocating ACE array",
366 acl_size = sizeof(struct cifs_ctrl_acl);
367 for (i = 0; i < numfaces; ++i) {
368 facesptr[i] = malloc(sizeof(struct cifs_ace));
371 goto build_fetched_aces_ret;
373 pace = (struct cifs_ace *) (acl_base + acl_size);
374 memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
375 acl_base = (char *)pace;
376 acl_size = le16toh(pace->size);
379 build_fetched_aces_ret:
381 printf("%s: Invalid fetched ace\n", __func__);
383 for (j = i; j >= 0; --j)
392 verify_ace_sid(char *sidstr, struct cifs_sid *sid)
396 struct passwd *winpswdptr;
398 lstr = strstr(sidstr, "\\"); /* everything before | */
404 /* Check if it is a (raw) SID (string) */
405 rc = wbcStringToSid(lstr, (struct wbcDomainSid *)sid);
409 /* Check if it a name (string) which can be resolved to a SID*/
410 rc = wbcGetpwnam(lstr, &winpswdptr);
412 printf("%s: Invalid user name: %s\n", __func__, sidstr);
415 rc = wbcUidToSid(winpswdptr->pw_uid, (struct wbcDomainSid *)sid);
417 printf("%s: Invalid user: %s\n", __func__, sidstr);
425 verify_ace_type(char *typestr, uint8_t *typeval)
430 if (strstr(typestr, "0x")) { /* hex type value */
431 *typeval = strtol(typestr, &invaltype, 16);
432 if (!strlen(invaltype)) {
433 if (*typeval != ACCESS_ALLOWED &&
434 *typeval != ACCESS_DENIED &&
435 *typeval != ACCESS_ALLOWED_OBJECT &&
436 *typeval != ACCESS_DENIED_OBJECT) {
437 printf("%s: Invalid type: %s\n",
445 len = strlen(typestr);
446 for (i = 0; i < len; ++i)
447 *(typestr + i) = toupper(*(typestr + i));
448 if (!strcmp(typestr, "ALLOWED"))
450 else if (!strcmp(typestr, "DENIED"))
452 else if (!strcmp(typestr, "ALLOWED_OBJECT"))
454 else if (!strcmp(typestr, "DENIED_OBJECT"))
457 printf("%s: Invalid type: %s\n", __func__, typestr);
465 ace_flag_value(char *flagstr)
467 uint8_t flagval = 0x0;
470 iflag = strtok(flagstr, "|"); /* everything before | */
472 if (!strcmp(iflag, "OI"))
474 else if (!strcmp(iflag, "CI"))
476 else if (!strcmp(iflag, "NP"))
478 else if (!strcmp(iflag, "IO"))
480 else if (!strcmp(iflag, "I"))
483 return 0x0; /* Invalid flag */
484 iflag = strtok(NULL, "|"); /* everything before | */
491 verify_ace_flags(char *flagstr, uint8_t *flagval)
495 if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
498 if (strstr(flagstr, "0x")) { /* hex flag value */
499 *flagval = strtol(flagstr, &invalflag, 16);
500 if (strlen(invalflag)) {
501 printf("%s: Invalid flags: %s\n", __func__, flagstr);
505 *flagval = ace_flag_value(flagstr);
507 if (!*flagval || (*flagval & ~VFLAGS)) {
508 printf("%s: Invalid flag %s and value: 0x%x\n",
509 __func__, flagstr, *flagval);
517 ace_mask_value(char *maskstr)
520 uint32_t maskval = 0x0;
523 if (!strcmp(maskstr, "FULL"))
525 else if (!strcmp(maskstr, "CHANGE"))
527 else if (!strcmp(maskstr, "D"))
529 else if (!strcmp(maskstr, "READ"))
532 len = strlen(maskstr);
534 for (i = 0; i < len; ++i, ++lmask) {
537 else if (*lmask == 'W')
539 else if (*lmask == 'X')
541 else if (*lmask == 'D')
543 else if (*lmask == 'P')
544 maskval |= WRITE_DAC;
545 else if (*lmask == 'O')
546 maskval |= WRITE_OWNER;
557 verify_ace_mask(char *maskstr, uint32_t *maskval)
561 if (strstr(maskstr, "0x") || !strcmp(maskstr, "DELDHLD")) {
562 *maskval = strtol(maskstr, &invalflag, 16);
564 printf("%s: Invalid mask: %s\n", __func__, maskstr);
568 *maskval = ace_mask_value(maskstr);
571 printf("%s: Invalid mask %s and value: 0x%x\n",
572 __func__, maskstr, *maskval);
579 static struct cifs_ace **
580 build_cmdline_aces(char **arrptr, int numcaces)
583 char *acesid, *acetype, *aceflag, *acemask;
584 struct cifs_ace **cacesptr;
586 cacesptr = (struct cifs_ace **)malloc(numcaces *
587 sizeof(struct cifs_aces *));
589 printf("%s: Error %d allocating ACE array", __func__, errno);
593 for (i = 0; i < numcaces; ++i) {
594 acesid = strtok(arrptr[i], ":");
595 acetype = strtok(NULL, "/");
596 aceflag = strtok(NULL, "/");
597 acemask = strtok(NULL, "/");
599 if (!acesid || !acetype || !aceflag || !acemask) {
600 printf("%s: Incomplete ACE: %s\n", __func__, arrptr[i]);
601 goto build_cmdline_aces_ret;
604 cacesptr[i] = malloc(sizeof(struct cifs_ace));
606 printf("%s: ACE alloc error %d\n", __func__, errno);
607 goto build_cmdline_aces_ret;
610 if (verify_ace_sid(acesid, &cacesptr[i]->sid)) {
611 printf("%s: Invalid SID: %s\n", __func__, arrptr[i]);
612 goto build_cmdline_aces_ret;
615 if (verify_ace_type(acetype, &cacesptr[i]->type)) {
616 printf("%s: Invalid ACE type: %s\n",
617 __func__, arrptr[i]);
618 goto build_cmdline_aces_ret;
621 if (verify_ace_flags(aceflag, &cacesptr[i]->flags)) {
622 printf("%s: Invalid ACE flag: %s\n",
623 __func__, arrptr[i]);
624 goto build_cmdline_aces_ret;
627 if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
628 printf("%s: Invalid ACE mask: %s\n",
629 __func__, arrptr[i]);
630 goto build_cmdline_aces_ret;
633 cacesptr[i]->size = 1 + 1 + 2 + 4 + 1 + 1 + 6 +
634 (cacesptr[i]->sid.num_subauth * 4);
638 build_cmdline_aces_ret:
646 parse_cmdline_aces(char *optarg, int numcaces)
649 char *acestr, *vacestr, **arrptr = NULL;
652 arrptr = (char **)malloc(numcaces * sizeof(char *));
654 printf("%s: Error %d allocating char array\n", __func__, errno);
658 while (i < numcaces) {
659 acestr = strtok(optarg, ","); /* everything before , */
661 vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
663 vacestr = strchr(vacestr, ':');
665 ++vacestr; /* go past : */
667 len = strlen(vacestr);
668 arrptr[i] = malloc(len + 1);
670 goto parse_cmdline_aces_ret;
671 strcpy(arrptr[i], vacestr);
674 goto parse_cmdline_aces_ret;
676 goto parse_cmdline_aces_ret;
678 goto parse_cmdline_aces_ret;
684 parse_cmdline_aces_ret:
685 printf("%s: Error %d parsing ACEs\n", __func__, errno);
693 get_numcaces(const char *optarg)
696 unsigned int numcaces = 1;
701 len = strlen(optarg);
702 for (i = 0; i < len; ++i) {
703 if (*(optarg + i) == ',')
711 setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
712 ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
713 struct cifs_ace **cacesptr, int numcaces,
720 rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
721 numfaces, cacesptr, numcaces);
724 rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
725 numfaces, cacesptr, numcaces);
728 rc = ace_add(pntsd, npntsd, bufsize, facesptr,
729 numfaces, cacesptr, numcaces);
732 rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
735 printf("%s: Invalid action: %d\n", __func__, maction);
743 setcifsacl_usage(void)
746 "%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
748 fprintf(stderr, "Usage: %s option <list_of_ACEs> <file_name>\n", prog);
749 fprintf(stderr, "Valid options:\n");
750 fprintf(stderr, "\t-v Version of the program\n");
751 fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
753 "\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
754 fprintf(stderr, "\n");
756 "\t-D Delete ACE(s), separated by a comma, from an ACL\n");
758 "\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
759 fprintf(stderr, "\n");
761 "\t-M Modify ACE(s), separated by a comma, in an ACL\n");
763 "\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
765 "\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
767 "\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
768 fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
772 main(const int argc, char *const argv[])
774 int i, rc, c, numcaces, numfaces, maction = -1;
775 ssize_t attrlen, bufsize = BUFSIZE;
776 char *filename, *attrval, **arrptr = NULL;
777 struct cifs_ctrl_acl *daclptr = NULL;
778 struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
779 struct cifs_ntsd *ntsdptr = NULL;
781 openlog(prog, 0, LOG_DAEMON);
783 c = getopt(argc, argv, "v:D:M:a:S:?");
786 printf("Version: %s\n", VERSION);
813 numcaces = get_numcaces(optarg);
815 printf("%s: No valid ACEs specified\n", __func__);
819 arrptr = parse_cmdline_aces(optarg, numcaces);
821 goto setcifsacl_numcaces_ret;
823 cacesptr = build_cmdline_aces(arrptr, numcaces);
825 goto setcifsacl_cmdlineparse_ret;
828 if (bufsize >= XATTR_SIZE_MAX) {
829 printf("%s: Buffer size %ld exceeds max size of %d\n",
830 __func__, bufsize, XATTR_SIZE_MAX);
831 goto setcifsacl_cmdlineverify_ret;
834 attrval = malloc(bufsize * sizeof(char));
836 printf("error allocating memory for attribute value buffer\n");
837 goto setcifsacl_cmdlineverify_ret;
840 attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
842 if (errno == ERANGE) {
847 printf("getxattr error: %d\n", errno);
848 goto setcifsacl_getx_ret;
852 numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
853 if (!numfaces && maction != 2) { /* if we are not adding aces */
854 printf("%s: Empty DACL\n", __func__);
855 goto setcifsacl_facenum_ret;
858 facesptr = build_fetched_aces((char *)daclptr, numfaces);
860 goto setcifsacl_facenum_ret;
863 rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
864 facesptr, numfaces, cacesptr, numcaces, maction);
866 goto setcifsacl_action_ret;
868 attrlen = setxattr(filename, ATTRNAME, ntsdptr, bufsize, 0);
870 printf("%s: setxattr error: %s\n", __func__, strerror(errno));
871 goto setcifsacl_facenum_ret;
876 setcifsacl_action_ret:
879 setcifsacl_facenum_ret:
880 for (i = 0; i < numfaces; ++i)
887 setcifsacl_cmdlineverify_ret:
888 for (i = 0; i < numcaces; ++i)
892 setcifsacl_cmdlineparse_ret:
893 for (i = 0; i < numcaces; ++i)
897 setcifsacl_numcaces_ret: