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;
44 enum setcifsacl_actions {
53 copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
57 dst->revision = src->revision;
58 dst->num_subauth = src->num_subauth;
59 for (i = 0; i < NUM_AUTHS; i++)
60 dst->authority[i] = src->authority[i];
61 for (i = 0; i < src->num_subauth; i++)
62 dst->sub_auth[i] = src->sub_auth[i];
66 copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
67 int numaces, int acessize)
69 int osidsoffset, gsidsoffset, dacloffset;
70 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
71 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
72 struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
74 /* copy security descriptor control portion */
75 osidsoffset = le32toh(pntsd->osidoffset);
76 gsidsoffset = le32toh(pntsd->gsidoffset);
77 dacloffset = le32toh(pntsd->dacloffset);
79 pnntsd->revision = pntsd->revision;
80 pnntsd->type = pntsd->type;
81 pnntsd->osidoffset = pntsd->osidoffset;
82 pnntsd->gsidoffset = pntsd->gsidoffset;
83 pnntsd->dacloffset = pntsd->dacloffset;
85 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
86 ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
88 ndacl_ptr->revision = dacl_ptr->revision;
89 ndacl_ptr->size = htole16(acessize + sizeof(struct cifs_ctrl_acl));
90 ndacl_ptr->num_aces = htole32(numaces);
93 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
94 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
95 copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
98 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
99 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
100 copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
106 copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
108 dace->type = sace->type;
109 dace->flags = sace->flags;
110 dace->access_req = sace->access_req;
112 copy_cifs_sid(&dace->sid, &sace->sid);
114 dace->size = sace->size;
116 return le16toh(dace->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 != 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;
332 dacloffset = le32toh(pntsd->dacloffset);
336 ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
338 /* validate that we do not go past end of acl */
339 if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
340 numfaces = le32toh(ldaclptr->num_aces);
347 static struct cifs_ace **
348 build_fetched_aces(char *daclptr, int numfaces)
352 struct cifs_ace *pace, **facesptr;
354 facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
356 printf("%s: Error %d allocating ACE array",
362 acl_size = sizeof(struct cifs_ctrl_acl);
363 for (i = 0; i < numfaces; ++i) {
364 facesptr[i] = malloc(sizeof(struct cifs_ace));
366 goto build_fetched_aces_err;
367 pace = (struct cifs_ace *) (acl_base + acl_size);
368 memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
369 acl_base = (char *)pace;
370 acl_size = le16toh(pace->size);
374 build_fetched_aces_err:
375 printf("%s: Invalid fetched ace\n", __func__);
376 for (i = 0; i < numfaces; ++i)
383 verify_ace_sid(char *sidstr, struct cifs_sid *sid)
388 enum wbcSidType type;
390 name = strchr(sidstr, '\\');
392 /* might be a raw string representation of SID */
393 rc = wbcStringToSid(sidstr, (struct wbcDomainSid *)sid);
394 if (WBC_ERROR_IS_OK(rc))
405 rc = wbcLookupName(domain, name, (struct wbcDomainSid *)sid, &type);
406 if (!WBC_ERROR_IS_OK(rc)) {
407 printf("%s: Error converting %s\\%s to SID: %s\n",
408 __func__, domain, name, wbcErrorString(rc));
414 * Winbind keeps wbcDomainSid fields in host-endian. So, we must
415 * convert that to little endian since the server will expect that.
417 for (i = 0; i < sid->num_subauth; i++)
418 sid->sub_auth[i] = htole32(sid->sub_auth[i]);
423 verify_ace_type(char *typestr, uint8_t *typeval)
428 if (strstr(typestr, "0x")) { /* hex type value */
429 *typeval = strtol(typestr, &invaltype, 16);
430 if (!strlen(invaltype)) {
431 if (*typeval != ACCESS_ALLOWED &&
432 *typeval != ACCESS_DENIED &&
433 *typeval != ACCESS_ALLOWED_OBJECT &&
434 *typeval != ACCESS_DENIED_OBJECT) {
435 printf("%s: Invalid type: %s\n",
443 len = strlen(typestr);
444 for (i = 0; i < len; ++i)
445 *(typestr + i) = toupper(*(typestr + i));
446 if (!strcmp(typestr, "ALLOWED"))
448 else if (!strcmp(typestr, "DENIED"))
450 else if (!strcmp(typestr, "ALLOWED_OBJECT"))
452 else if (!strcmp(typestr, "DENIED_OBJECT"))
455 printf("%s: Invalid type: %s\n", __func__, typestr);
463 ace_flag_value(char *flagstr)
465 uint8_t flagval = 0x0;
468 iflag = strtok(flagstr, "|"); /* everything before | */
470 if (!strcmp(iflag, "OI"))
472 else if (!strcmp(iflag, "CI"))
474 else if (!strcmp(iflag, "NP"))
476 else if (!strcmp(iflag, "IO"))
478 else if (!strcmp(iflag, "I"))
481 return 0x0; /* Invalid flag */
482 iflag = strtok(NULL, "|"); /* everything before | */
489 verify_ace_flags(char *flagstr, uint8_t *flagval)
493 if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
496 if (strstr(flagstr, "0x")) { /* hex flag value */
497 *flagval = strtol(flagstr, &invalflag, 16);
498 if (strlen(invalflag)) {
499 printf("%s: Invalid flags: %s\n", __func__, flagstr);
503 *flagval = ace_flag_value(flagstr);
505 if (!*flagval || (*flagval & ~VFLAGS)) {
506 printf("%s: Invalid flag %s and value: 0x%x\n",
507 __func__, flagstr, *flagval);
515 ace_mask_value(char *maskstr)
518 uint32_t maskval = 0x0;
521 if (!strcmp(maskstr, "FULL"))
523 else if (!strcmp(maskstr, "CHANGE"))
525 else if (!strcmp(maskstr, "D"))
527 else if (!strcmp(maskstr, "READ"))
530 len = strlen(maskstr);
532 for (i = 0; i < len; ++i, ++lmask) {
535 else if (*lmask == 'W')
537 else if (*lmask == 'X')
539 else if (*lmask == 'D')
541 else if (*lmask == 'P')
542 maskval |= WRITE_DAC;
543 else if (*lmask == 'O')
544 maskval |= WRITE_OWNER;
555 verify_ace_mask(char *maskstr, uint32_t *maskval)
559 if (strstr(maskstr, "0x") || !strcmp(maskstr, "DELDHLD")) {
560 *maskval = strtol(maskstr, &invalflag, 16);
562 printf("%s: Invalid mask: %s\n", __func__, maskstr);
566 *maskval = ace_mask_value(maskstr);
569 printf("%s: Invalid mask %s and value: 0x%x\n",
570 __func__, maskstr, *maskval);
577 static struct cifs_ace **
578 build_cmdline_aces(char **arrptr, int numcaces)
581 char *acesid, *acetype, *aceflag, *acemask;
582 struct cifs_ace **cacesptr;
584 cacesptr = calloc(numcaces, sizeof(struct cifs_aces *));
586 printf("%s: Error %d allocating ACE array", __func__, errno);
590 for (i = 0; i < numcaces; ++i) {
591 acesid = strtok(arrptr[i], ":");
592 acetype = strtok(NULL, "/");
593 aceflag = strtok(NULL, "/");
594 acemask = strtok(NULL, "/");
596 if (!acesid || !acetype || !aceflag || !acemask) {
597 printf("%s: Incomplete ACE: %s\n", __func__, arrptr[i]);
598 goto build_cmdline_aces_ret;
601 cacesptr[i] = malloc(sizeof(struct cifs_ace));
603 printf("%s: ACE alloc error %d\n", __func__, errno);
604 goto build_cmdline_aces_ret;
607 if (verify_ace_sid(acesid, &cacesptr[i]->sid)) {
608 printf("%s: Invalid SID: %s\n", __func__, arrptr[i]);
609 goto build_cmdline_aces_ret;
612 if (verify_ace_type(acetype, &cacesptr[i]->type)) {
613 printf("%s: Invalid ACE type: %s\n",
614 __func__, arrptr[i]);
615 goto build_cmdline_aces_ret;
618 if (verify_ace_flags(aceflag, &cacesptr[i]->flags)) {
619 printf("%s: Invalid ACE flag: %s\n",
620 __func__, arrptr[i]);
621 goto build_cmdline_aces_ret;
624 if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
625 printf("%s: Invalid ACE mask: %s\n",
626 __func__, arrptr[i]);
627 goto build_cmdline_aces_ret;
630 cacesptr[i]->size = 1 + 1 + 2 + 4 + 1 + 1 + 6 +
631 (cacesptr[i]->sid.num_subauth * 4);
635 build_cmdline_aces_ret:
636 for (i = 0; i < numcaces; ++i)
643 parse_cmdline_aces(char *acelist, int numcaces)
646 char *acestr, *vacestr, **arrptr = NULL;
648 arrptr = (char **)malloc(numcaces * sizeof(char *));
650 printf("%s: Unable to allocate char array\n", __func__);
654 while (i < numcaces) {
655 acestr = strtok(acelist, ","); /* everything before , */
657 goto parse_cmdline_aces_err;
659 vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
661 goto parse_cmdline_aces_err;
662 vacestr += 4; /* skip past "ACL:" */
671 parse_cmdline_aces_err:
672 printf("%s: Error parsing ACEs\n", __func__);
677 /* How many aces were provided on the command-line? Count the commas. */
679 get_numcaces(const char *aces)
682 unsigned int num = 1;
686 while((current = strchr(current, ',')))
693 setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
694 ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
695 struct cifs_ace **cacesptr, int numcaces,
696 enum setcifsacl_actions maction)
702 rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
703 numfaces, cacesptr, numcaces);
706 rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
707 numfaces, cacesptr, numcaces);
710 rc = ace_add(pntsd, npntsd, bufsize, facesptr,
711 numfaces, cacesptr, numcaces);
714 rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
717 printf("%s: Invalid action: %d\n", __func__, maction);
725 setcifsacl_usage(void)
728 "%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
730 fprintf(stderr, "Usage: %s option <list_of_ACEs> <file_name>\n", prog);
731 fprintf(stderr, "Valid options:\n");
732 fprintf(stderr, "\t-v Version of the program\n");
733 fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
735 "\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
736 fprintf(stderr, "\n");
738 "\t-D Delete ACE(s), separated by a comma, from an ACL\n");
740 "\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
741 fprintf(stderr, "\n");
743 "\t-M Modify ACE(s), separated by a comma, in an ACL\n");
745 "\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
747 "\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
749 "\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
750 fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
754 main(const int argc, char *const argv[])
756 int i, rc, c, numcaces, numfaces;
757 enum setcifsacl_actions maction = ActUnknown;
758 ssize_t attrlen, bufsize = BUFSIZE;
759 char *ace_list, *filename, *attrval, **arrptr = NULL;
760 struct cifs_ctrl_acl *daclptr = NULL;
761 struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
762 struct cifs_ntsd *ntsdptr = NULL;
764 prog = basename(argv[0]);
766 openlog(prog, 0, LOG_DAEMON);
768 c = getopt(argc, argv, "hvD:M:a:S:");
790 printf("Version: %s\n", VERSION);
797 /* We expect 1 argument in addition to the option */
805 printf("%s: No valid ACEs specified\n", __func__);
809 numcaces = get_numcaces(ace_list);
811 arrptr = parse_cmdline_aces(ace_list, numcaces);
813 goto setcifsacl_numcaces_ret;
815 cacesptr = build_cmdline_aces(arrptr, numcaces);
817 goto setcifsacl_cmdlineparse_ret;
820 if (bufsize >= XATTR_SIZE_MAX) {
821 printf("%s: Buffer size %ld exceeds max size of %d\n",
822 __func__, bufsize, XATTR_SIZE_MAX);
823 goto setcifsacl_cmdlineverify_ret;
826 attrval = malloc(bufsize * sizeof(char));
828 printf("error allocating memory for attribute value buffer\n");
829 goto setcifsacl_cmdlineverify_ret;
832 attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
834 if (errno == ERANGE) {
839 printf("getxattr error: %d\n", errno);
840 goto setcifsacl_getx_ret;
844 numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
845 if (!numfaces && maction != ActAdd) { /* if we are not adding aces */
846 printf("%s: Empty DACL\n", __func__);
847 goto setcifsacl_facenum_ret;
850 facesptr = build_fetched_aces((char *)daclptr, numfaces);
852 goto setcifsacl_facenum_ret;
855 rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
856 facesptr, numfaces, cacesptr, numcaces, maction);
858 goto setcifsacl_action_ret;
860 attrlen = setxattr(filename, ATTRNAME, ntsdptr, bufsize, 0);
862 printf("%s: setxattr error: %s\n", __func__, strerror(errno));
863 goto setcifsacl_facenum_ret;
867 setcifsacl_action_ret:
870 setcifsacl_facenum_ret:
871 for (i = 0; i < numfaces; ++i)
878 setcifsacl_cmdlineverify_ret:
879 for (i = 0; i < numcaces; ++i)
883 setcifsacl_cmdlineparse_ret:
886 setcifsacl_numcaces_ret: