cifs-utils: bump version to 7.0
[cifs-utils.git] / setcifsacl.c
1 /*
2 * setcifsacl utility
3 *
4 * Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
5 *
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.
9 *
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
21 */
22
23 /*
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
32  *
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.
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif /* HAVE_CONFIG_H */
40
41 #include <string.h>
42 #include <getopt.h>
43 #include <stdint.h>
44 #include <stdbool.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <limits.h>
50 #include <ctype.h>
51 #include <sys/xattr.h>
52
53 #include "cifsacl.h"
54 #include "idmap_plugin.h"
55
56 enum setcifsacl_actions {
57         ActUnknown = -1,
58         ActDelete,
59         ActModify,
60         ActAdd,
61         ActSetAcl,
62         ActSetOwner,
63         ActSetGroup,
64         ActSetSacl,
65         ActAddReorder
66 };
67
68 static void *plugin_handle;
69 static bool plugin_loaded;
70
71 static int
72 copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
73 {
74         int i, size = 0;
75
76         dst->revision = src->revision;
77         size += sizeof(uint8_t);
78
79         dst->num_subauth = src->num_subauth;
80         size += sizeof(uint8_t);
81
82         for (i = 0; i < NUM_AUTHS; i++)
83                 dst->authority[i] = src->authority[i];
84         size += (sizeof(uint8_t) * NUM_AUTHS);
85
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);
89
90         return size;
91 }
92
93 static int
94 get_cifs_sid_size(const struct cifs_sid *sid)
95 {
96         return (2 * sizeof(uint8_t) +
97                 sizeof(uint8_t) * NUM_AUTHS +
98                 sizeof(uint32_t) * sid->num_subauth);
99 }
100
101 /*
102  * This function takes a pointer of the fetched (original) descriptor, and
103  * it returns the offset of the ACL in the new descriptor.
104  *
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
112  * of group SID.
113  * @todo: need to add a command-line argument to know if this is
114  *        Azure-style descriptor or a regular-style descriptor
115  */
116 static int get_aces_offset(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
117         int dacloffset, sacloffset, acesoffset;
118
119         switch(ace_kind) {
120         case ACE_KIND_SACL:
121                 sacloffset = le32toh(pntsd->sacloffset);
122                 if (sacloffset) {
123                         acesoffset = sacloffset + sizeof(struct cifs_ctrl_acl);
124                 } else {
125                         dacloffset = le32toh(pntsd->dacloffset);
126                         if (dacloffset) {
127                                 struct cifs_ctrl_acl *dacl_ptr =
128                                         (struct cifs_ctrl_acl *)((char *)pntsd +
129                                                         dacloffset);
130                                 acesoffset = dacloffset +
131                                         le16toh(dacl_ptr->size) +
132                                         sizeof(struct cifs_ctrl_acl);
133                         } else {
134                                 int gsidoffset = le32toh(pntsd->gsidoffset);
135                                 struct cifs_sid *group_sid_ptr =
136                                         (struct cifs_sid *)((char *)pntsd +
137                                                         gsidoffset);
138                                 int gsidsize = get_cifs_sid_size(group_sid_ptr);
139                                 acesoffset = gsidoffset + gsidsize +
140                                         sizeof(struct cifs_ctrl_acl);
141                         }
142                 }
143                 break;
144         case ACE_KIND_DACL:
145         default:
146                 dacloffset = le32toh(pntsd->dacloffset);
147                 if (dacloffset) {
148                         acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
149                 } else {
150                         int gsidoffset = le32toh(pntsd->gsidoffset);
151                         struct cifs_sid *group_sid_ptr =
152                                 (struct cifs_sid *)((char *)pntsd +
153                                                 gsidoffset);
154                         int gsidsize = get_cifs_sid_size(group_sid_ptr);
155                         acesoffset = gsidoffset + gsidsize +
156                                 sizeof(struct cifs_ctrl_acl);
157                 }
158                 break;
159         }
160         return acesoffset;
161 }
162
163 int get_aces_size(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
164         int acloffset, size;
165         struct cifs_ctrl_acl *acl_ptr;
166
167         switch(ace_kind) {
168         case ACE_KIND_SACL:
169                 acloffset = le32toh(pntsd->sacloffset);
170                 break;
171         case ACE_KIND_DACL:
172         default:
173                 acloffset = le32toh(pntsd->dacloffset);
174         }
175         if (acloffset) {
176                 acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + acloffset);
177                 size = le16toh(acl_ptr->size);
178         } else {
179                 size = 0;
180         }
181         return size;
182 }
183
184 uint16_t get_acl_revision(const struct cifs_ntsd *pntsd, ace_kinds ace_kind) {
185         struct cifs_ctrl_acl *acl_ptr;
186         int acloffset;
187         switch(ace_kind) {
188         case ACE_KIND_SACL:
189                 acloffset = le32toh(pntsd->sacloffset);
190                 if (acloffset) {
191                         acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd +
192                                                            acloffset);
193                         return acl_ptr->revision;
194                 }
195         /* intentional fall through */
196         case ACE_KIND_DACL:
197         default:
198                 acloffset = le32toh(pntsd->dacloffset);
199                 if (acloffset) {
200                         acl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd +
201                                                            acloffset);
202                         return acl_ptr->revision;
203                 } else {
204                         return DEFAULT_ACL_REVISION;
205                 }
206                 break;
207         }
208 }
209
210 /*
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.
214  */
215 static ssize_t
216 copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
217                 int numaces, int acessize, ace_kinds ace_kind)
218 {
219         int size, osidsoffset, gsidsoffset, acloffset, dacloffset;
220         ssize_t bufsize;
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;
224         char *ndacl_ptr;
225
226         /* copy security descriptor control portion */
227         osidsoffset = le32toh(pntsd->osidoffset);
228         gsidsoffset = le32toh(pntsd->gsidoffset);
229
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;
236         bufsize = size;
237
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);
241
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);
247                 if (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);
252                         bufsize += size;
253                 }
254                 /* initialize SACL offset */
255                 pnntsd->sacloffset = acloffset;
256         }
257
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);
263         bufsize += size;
264
265         /* copy owner sid */
266
267         /*
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
270          */
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);
277                 bufsize += size;
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);
282         } else {
283                 /*
284                  * Most servers put the owner information at the beginning,
285                  * before the ACL
286                  */
287                 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
288                 size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
289                 bufsize += size;
290                 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
291         }
292
293         /* copy group sid */
294         size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
295         bufsize += size;
296
297         return bufsize;
298 }
299
300 /*
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.
304  */
305 static ssize_t
306 copy_sec_desc_with_sid(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
307                 struct cifs_sid *sid, int maction)
308 {
309         int size, daclsize;
310         int osidoffset, gsidoffset, dacloffset;
311         int nosidoffset, ngsidoffset, ndacloffset, nsidssize;
312         ssize_t bufsize;
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;
316
317         /* copy security descriptor control portion */
318         osidoffset = le32toh(pntsd->osidoffset);
319         gsidoffset = le32toh(pntsd->gsidoffset);
320         dacloffset = le32toh(pntsd->dacloffset);
321         /*
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
326          */
327         nosidoffset = osidoffset;
328         size = sizeof(struct cifs_ntsd);
329         pnntsd->revision = pntsd->revision;
330         pnntsd->type = pntsd->type;
331         pnntsd->osidoffset = pntsd->osidoffset;
332         bufsize = size;
333
334         /* set the pointers for source sids */
335         if (maction == ActSetOwner) {
336                 owner_sid_ptr = sid;
337                 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidoffset);
338         }
339         if (maction == ActSetGroup) {
340                 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidoffset);
341                 group_sid_ptr = sid;
342         }
343
344         if (dacloffset) {
345                 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
346                 daclsize = le16toh(dacl_ptr->size) + sizeof(struct cifs_ctrl_acl);
347         } else {
348                 dacl_ptr = NULL;
349                 daclsize = 0;
350         }
351
352         /* copy owner sid */
353         nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + nosidoffset);
354         size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
355         bufsize += size;
356         nsidssize = size;
357
358         /* copy group sid */
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);
363         bufsize += size;
364         nsidssize += size;
365
366         /* position the dacl control info as in the fetched descriptor */
367         if (dacloffset) {
368                 if (dacloffset <= osidoffset)
369                         ndacloffset = dacloffset;
370                 else
371                         ndacloffset = nosidoffset + nsidssize;
372                 ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + ndacloffset);
373                 pnntsd->dacloffset = htole32(ndacloffset);
374
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;
379         } else {
380                 pnntsd->dacloffset = 0;
381         }
382         /*
383          * add DACL size (control portion and the array of aces) to the
384          * buffer size
385          */
386         bufsize += daclsize;
387
388         return bufsize;
389 }
390
391 static int
392 copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
393 {
394         dace->type = sace->type;
395         dace->flags = sace->flags;
396         dace->access_req = sace->access_req;
397
398         copy_cifs_sid(&dace->sid, &sace->sid);
399
400         dace->size = sace->size;
401
402         return le16toh(dace->size);
403 }
404
405 static int
406 compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
407 {
408         int i;
409
410         if (compflags & COMPSID) {
411                 if (dace->sid.revision != sace->sid.revision)
412                         return 0;
413                 if (dace->sid.num_subauth != sace->sid.num_subauth)
414                         return 0;
415                 for (i = 0; i < NUM_AUTHS; i++) {
416                         if (dace->sid.authority[i] != sace->sid.authority[i])
417                                 return 0;
418                 }
419                 for (i = 0; i < sace->sid.num_subauth; i++) {
420                         if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
421                                 return 0;
422                 }
423         }
424
425         if (compflags & COMPTYPE) {
426                 if (dace->type != sace->type)
427                         return 0;
428         }
429
430         if (compflags & COMPFLAG) {
431                 if (dace->flags != sace->flags)
432                         return 0;
433         }
434
435         if (compflags & COMPMASK) {
436                 if (dace->access_req != sace->access_req)
437                         return 0;
438         }
439
440         return 1;
441 }
442
443 /*
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
449  * the aces).
450  * When setting SACL, we allocate sufficient space to copy the above components
451  * plus the SACL to be set (ACL controla and aces).
452  */
453 static int
454 alloc_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
455                 int aces, size_t *acesoffset, ace_kinds ace_kind)
456 {
457         unsigned int size, acessize, bufsize;
458
459         switch(ace_kind) {
460         case ACE_KIND_SACL:
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);
466                 break;
467         case ACE_KIND_DACL:
468         default:
469                 size = sizeof(struct cifs_ntsd) +
470                         2 * sizeof(struct cifs_sid) +
471                         sizeof(struct cifs_ctrl_acl);
472                 break;
473         }
474
475         *acesoffset = get_aces_offset(pntsd, ace_kind);
476         acessize = aces * sizeof(struct cifs_ace);
477         bufsize = size + acessize;
478         *npntsd = calloc(1, bufsize);
479         if (!*npntsd) {
480                 fprintf(stderr, "%s: Memory allocation failure", __func__);
481                 return errno;
482         }
483
484         return 0;
485 }
486
487 static struct cifs_ace **
488 build_reorder_aces(struct cifs_ace **facesptr, int numfaces)
489 {
490         struct cifs_ace *pace, **allowedacesptr, **deniedacesptr,
491                         **allowedinhacesptr, **deniedinhacesptr, **reorderacesptr;
492         int i, numallowedaces, numdeniedaces,
493             numallowedinhaces, numdeniedinhaces, numreorderaces;
494
495         allowedacesptr = calloc(numfaces, sizeof(struct cifs_ace *));
496         deniedacesptr = calloc(numfaces, sizeof(struct cifs_ace *));
497         allowedinhacesptr = calloc(numfaces, sizeof(struct cifs_ace *));
498         deniedinhacesptr = calloc(numfaces, sizeof(struct cifs_ace *));
499         reorderacesptr = calloc(numfaces, sizeof(struct cifs_ace *));
500
501         numallowedaces = 0;
502         numdeniedaces = 0;
503         numallowedinhaces = 0;
504         numdeniedinhaces = 0;
505         numreorderaces = 0;
506
507         for (i = 0; i < numfaces; i++) {
508                 pace = facesptr[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));
513                                 numdeniedaces++;
514                         } else {
515                                 deniedinhacesptr[numdeniedinhaces] = malloc(sizeof(struct cifs_ace));
516                                 memcpy(deniedinhacesptr[numdeniedinhaces], pace, sizeof(struct cifs_ace));
517                                 numdeniedinhaces++;
518                         }
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));
523                                 numallowedaces++;
524                         } else {
525                                 allowedinhacesptr[numallowedinhaces] = malloc(sizeof(struct cifs_ace));
526                                 memcpy(allowedinhacesptr[numallowedinhaces], pace, sizeof(struct cifs_ace));
527                                 numallowedinhaces++;
528                         }
529                 }
530         }
531
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));
535                 numreorderaces++;
536                 free(deniedacesptr[i]);
537         }
538
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));
542                 numreorderaces++;
543                 free(allowedacesptr[i]);
544         }
545
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));
549                 numreorderaces++;
550                 free(deniedinhacesptr[i]);
551         }
552
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));
556                 numreorderaces++;
557                 free(allowedinhacesptr[i]);
558         }
559
560         free(deniedacesptr);
561         free(allowedacesptr);
562         free(deniedinhacesptr);
563         free(allowedinhacesptr);
564
565         return reorderacesptr;
566 }
567
568 static int
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)
571 {
572         int i, rc, size = 0, acessize = 0;
573         size_t acesoffset;
574         char *acesptr;
575
576         rc = alloc_sec_desc(pntsd, npntsd, numcaces, &acesoffset, ace_kind);
577         if (rc)
578                 return rc;
579
580         acesptr = (char *)*npntsd + acesoffset;
581         for (i = 0; i < numcaces; ++i) {
582                 size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
583                 acessize += size;
584                 acesptr += size;
585         }
586
587         *bufsize = copy_sec_desc(pntsd, *npntsd, numcaces, acessize, ace_kind);
588
589         return 0;
590 }
591
592 static int
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,
596                 ace_kinds ace_kind)
597 {
598         int i, rc, numaces, size, acessize = 0;
599         size_t acesoffset;
600         char *acesptr;
601
602         numaces = numfaces + numcaces;
603         rc = alloc_sec_desc(pntsd, npntsd, numaces, &acesoffset, ace_kind);
604         if (rc)
605                 return rc;
606
607         acesptr = (char *)*npntsd + acesoffset;
608         for (i = 0; i < numfaces; ++i) {
609                 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
610                 acesptr += size;
611                 acessize += size;
612         }
613         for (i = 0; i < numcaces; ++i) {
614                 size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
615                 acesptr += size;
616                 acessize += size;
617         }
618
619         *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize, ace_kind);
620
621         return 0;
622 }
623
624 static int
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,
628                 ace_kinds ace_kind)
629 {
630         struct cifs_ace **reorderacesptr, **totalacesptr;
631         int i, rc, numaces;
632
633         numaces = numfaces + numcaces;
634         totalacesptr = calloc(numaces, sizeof(struct cifs_ace *));
635
636         for (i = 0; i < numfaces; i++) {
637                 totalacesptr[i] = facesptr[i];
638         }
639
640         for (i = numfaces; i < numaces; i++) {
641                 totalacesptr[i] = cacesptr[i - numfaces];
642         }
643
644         reorderacesptr = build_reorder_aces(totalacesptr, numaces);
645         rc = ace_add(pntsd, npntsd, bufsize, reorderacesptr,
646                         numaces, cacesptr, 0, ace_kind);
647
648         free(totalacesptr);
649         free(reorderacesptr);
650         return rc;
651 }
652
653 static int
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,
657                 ace_kinds ace_kind)
658 {
659         int i, j, rc, size, acessize = 0;
660         size_t acesoffset;
661         char *acesptr;
662
663         if (numfaces == 0) {
664                 fprintf(stderr, "%s: No entries to modify", __func__);
665                 return -1;
666         }
667
668         rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset, ace_kind);
669         if (rc)
670                 return rc;
671
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]);
677                                 break;
678                         }
679                 }
680         }
681
682         acesptr = (char *)*npntsd + acesoffset;
683         for (i = 0; i < numfaces; ++i) {
684                 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
685                 acesptr += size;
686                 acessize += size;
687         }
688
689         *bufsize = copy_sec_desc(pntsd, *npntsd, numfaces, acessize, ace_kind);
690
691         return 0;
692 }
693
694 static int
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,
698                 ace_kinds ace_kind)
699 {
700         int i, j, numaces = 0, rc, size, acessize = 0;
701         size_t acesoffset;
702         char *acesptr;
703
704         if (numfaces == 0) {
705                 fprintf(stderr, "%s: No entries to delete\n", __func__);
706                 return -1;
707         }
708
709         if (numfaces < numcaces) {
710                 fprintf(stderr, "%s: Invalid entries to delete\n", __func__);
711                 return -1;
712         }
713
714         rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset, ace_kind);
715         if (rc)
716                 return rc;
717
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))
722                                 break;
723                 }
724                 if (j == numcaces) {
725                         size = copy_ace((struct cifs_ace *)acesptr,
726                                         facesptr[i]);
727                         acessize += size;
728                         acesptr += size;
729                         ++numaces;
730                 }
731         }
732
733         if (numaces == numfaces) {
734                 fprintf(stderr, "%s: Nothing to delete\n", __func__);
735                 return 1;
736         }
737
738         *bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize, ace_kind);
739
740         return 0;
741 }
742
743 static int
744 get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
745                 struct cifs_ctrl_acl **aclptr, ace_kinds ace_kind)
746 {
747         int numfaces = 0;
748         uint32_t acloffset;
749         struct cifs_ctrl_acl *laclptr;
750         char *end_of_acl = ((char *)pntsd) + acl_len;
751
752         switch(ace_kind) {
753         case ACE_KIND_SACL:
754                 acloffset = le32toh(pntsd->sacloffset);
755                 break;
756         case ACE_KIND_DACL:
757         default:
758                 acloffset = le32toh(pntsd->dacloffset);
759                 break;
760         }
761
762         if (!acloffset)
763                 return 0;
764
765         laclptr = (struct cifs_ctrl_acl *)((char *)pntsd + acloffset);
766
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);
770                 *aclptr = laclptr;
771         }
772
773         return numfaces;
774 }
775
776 static struct cifs_ace **
777 build_fetched_aces(char *aclptr, int numfaces)
778 {
779         int i, acl_size;
780         char *acl_base;
781         struct cifs_ace *pace, **facesptr;
782
783         facesptr = calloc(numfaces, sizeof(struct cifs_ace *));
784         if (!facesptr) {
785                 fprintf(stderr, "%s: Error %d allocating ACE array",
786                                 __func__, errno);
787                 return facesptr;
788         }
789
790         acl_base = aclptr;
791         acl_size = sizeof(struct cifs_ctrl_acl);
792         for (i = 0; i < numfaces; ++i) {
793                 facesptr[i] = malloc(sizeof(struct cifs_ace));
794                 if (!facesptr[i])
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);
800         }
801         return facesptr;
802
803 build_fetched_aces_err:
804         fprintf(stderr, "%s: Invalid fetched ace\n", __func__);
805         for (i = 0; i < numfaces; ++i)
806                 free(facesptr[i]);
807         free(facesptr);
808         return NULL;
809 }
810
811 static int
812 verify_ace_type(char *typestr, uint8_t *typeval, ace_kinds ace_kind)
813 {
814         int i, len;
815         char *invaltype;
816         uint8_t ace_type_mask;
817
818         switch(ace_kind) {
819         case ACE_KIND_SACL:
820                 ace_type_mask = SACL_VTYPES;
821                 break;
822         case ACE_KIND_DACL:
823         default:
824                 ace_type_mask = DACL_VTYPES;
825                 break;
826         }
827
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",
834                                         __func__, typestr);
835                                 return 1;
836                         }
837                         return 0;
838                 }
839         }
840
841         len = strlen(typestr);
842         switch(ace_kind) {
843         case ACE_KIND_SACL:
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;
860                 else {
861                         fprintf(stderr, "%s: Invalid type: %s\n", __func__,
862                                 typestr);
863                         return 1;
864                 }
865                 break;
866         case ACE_KIND_DACL:
867         default:
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;
878                 else {
879                 fprintf(stderr, "%s: Invalid type: %s\n", __func__, typestr);
880                         return 1;
881                 }
882                 break;
883         }
884
885         return 0;
886 }
887
888 static uint8_t
889 ace_flag_value(char *flagstr, ace_kinds ace_kind)
890 {
891         uint8_t flagval = 0x0;
892         char *iflag;
893
894         iflag = strtok(flagstr, "|"); /* everything before | */
895         switch(ace_kind) {
896         case ACE_KIND_SACL:
897                 while (iflag) {
898                         if (!strcmp(iflag, "SA"))
899                                 flagval |= SUCCESSFUL_ACCESS;
900                         else if (!strcmp(iflag, "FA"))
901                                 flagval |= FAILED_ACCESS;
902                         else
903                                 return 0x0; /* Invalid flag */
904                         iflag = strtok(NULL, "|"); /* everything before | */
905                 }
906                 break;
907         case ACE_KIND_DACL:
908         default:
909                 while (iflag) {
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;
920                         else
921                                 return 0x0; /* Invalid flag */
922                         iflag = strtok(NULL, "|"); /* everything before | */
923                 }
924                 break;
925         }
926
927         return flagval;
928 }
929
930 static int
931 verify_ace_flags(char *flagstr, uint8_t *flagval, ace_kinds ace_kind)
932 {
933         char *invalflag;
934         uint8_t ace_flag_mask = 0;
935
936         if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
937                 return 0;
938
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__,
943                                 flagstr);
944                         return 1;
945                 }
946         } else
947                 *flagval = ace_flag_value(flagstr, ace_kind);
948
949         switch(ace_kind) {
950         case ACE_KIND_SACL:
951                 ace_flag_mask = SACL_VFLAGS;
952                 break;
953         case ACE_KIND_DACL:
954         default:
955                 ace_flag_mask = DACL_VFLAGS;
956                 break;
957         }
958         if (!*flagval || (*flagval & ~ace_flag_mask)) {
959                 fprintf(stderr, "%s: Invalid flag %s and value: 0x%x\n",
960                         __func__, flagstr, *flagval);
961                 return 1;
962         }
963
964         return 0;
965 }
966
967 static uint32_t
968 ace_mask_value(char *mask)
969 {
970         uint32_t maskval = 0;
971         char cur;
972
973         if (!strcmp(mask, "FULL"))
974                 return FULL_CONTROL;
975         if (!strcmp(mask, "CHANGE"))
976                 return CHANGE;
977         if (!strcmp(mask, "READ"))
978                 return EREAD;
979         if (!strcmp(mask, "RWXDPO"))
980                 return ALL_ACCESS_BITS;
981
982         while((cur = *mask++)) {
983                 switch(cur) {
984                 case 'R':
985                         maskval |= EREAD;
986                         break;
987                 case 'W':
988                         maskval |= EWRITE;
989                         break;
990                 case 'X':
991                         maskval |= EXEC;
992                         break;
993                 case 'D':
994                         maskval |= DELETE;
995                         break;
996                 case 'P':
997                         maskval |= WRITE_DAC;
998                         break;
999                 case 'O':
1000                         maskval |= WRITE_OWNER;
1001                         break;
1002                 default:
1003                         return 0;
1004                 }
1005         }
1006         return maskval;
1007 }
1008
1009 static int
1010 verify_ace_mask(char *maskstr, uint32_t *maskval)
1011 {
1012         unsigned long val;
1013         char *ep;
1014
1015         errno = 0;
1016         val = strtoul(maskstr, &ep, 0);
1017         if (errno == 0 && *ep == '\0')
1018                 *maskval = htole32((uint32_t)val);
1019         else
1020                 *maskval = htole32(ace_mask_value(maskstr));
1021
1022         if (!*maskval) {
1023                 fprintf(stderr, "%s: Invalid mask %s (value 0x%x)\n", __func__,
1024                         maskstr, *maskval);
1025                 return 1;
1026         }
1027
1028         return 0;
1029 }
1030
1031 #define AUTHORITY_MASK (~(0xffffffffffffULL))
1032
1033 static int
1034 raw_str_to_sid(const char *str, struct cifs_sid *csid)
1035 {
1036         const char *p;
1037         char *q;
1038         unsigned long long x;
1039
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-\"";
1043                 return -EINVAL;
1044         }
1045
1046         /* Get the SID revision number */
1047         p = str + 2;
1048         x = strtoull(p, &q, 10);
1049         if (x == 0 || x > UCHAR_MAX || !q || *q != '-') {
1050                 plugin_errmsg = "Invalid SID revision number";
1051                 return -EINVAL;
1052         }
1053         csid->revision = (uint8_t)x;
1054
1055         /*
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.
1059          */
1060         p = q + 1;
1061         x = strtoull(p, &q, 0);
1062         if ((x & AUTHORITY_MASK) || !q || *q !='-') {
1063                 plugin_errmsg = "Invalid SID authority";
1064                 return -EINVAL;
1065         }
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;
1072
1073         /* now read the the subauthorities and store as __le32 vals */
1074         p = q + 1;
1075         csid->num_subauth = 0;
1076         while (csid->num_subauth < SID_MAX_SUB_AUTHORITIES) {
1077                 x = strtoul(p, &q, 10);
1078                 if (p == q)
1079                         break;
1080                 if (x > UINT_MAX) {
1081                         plugin_errmsg = "Invalid sub authority value";
1082                         return -EINVAL;
1083                 }
1084                 csid->sub_auth[csid->num_subauth++] = htole32((uint32_t)x);
1085
1086                 if (*q != '-')
1087                         break;
1088                 p = q + 1;
1089         }
1090
1091         /* IF we ended early, then the SID could not be converted */
1092         if (q && *q != '\0') {
1093                 plugin_errmsg = "Invalid sub authority value";
1094                 return -EINVAL;
1095         }
1096
1097         return 0;
1098 }
1099
1100 static int
1101 setcifsacl_str_to_sid(const char *str, struct cifs_sid *sid)
1102 {
1103         if (plugin_loaded)
1104                 return str_to_sid(plugin_handle, str, sid);
1105         return raw_str_to_sid(str, sid);
1106 }
1107
1108 static struct cifs_ace **
1109 build_cmdline_aces(char **arrptr, int numcaces, ace_kinds ace_kind)
1110 {
1111         int i;
1112         char *acesid, *acetype, *aceflag, *acemask;
1113         struct cifs_ace **cacesptr;
1114         uint32_t access_req = 0;
1115
1116         cacesptr = calloc(numcaces, sizeof(struct cifs_ace *));
1117         if (!cacesptr) {
1118                 fprintf(stderr, "%s: Error %d allocating ACE array", __func__,
1119                         errno);
1120                 return NULL;
1121         }
1122
1123         for (i = 0; i < numcaces; ++i) {
1124                 acesid = strtok(arrptr[i], ":");
1125                 acetype = strtok(NULL, "/");
1126                 aceflag = strtok(NULL, "/");
1127                 acemask = strtok(NULL, "/");
1128
1129                 if (!acesid || !acetype || !aceflag || !acemask) {
1130                         fprintf(stderr, "%s: Incomplete ACE: %s\n", __func__,
1131                                 arrptr[i]);
1132                         goto build_cmdline_aces_ret;
1133                 }
1134
1135                 cacesptr[i] = calloc(1, sizeof(struct cifs_ace));
1136                 if (!cacesptr[i]) {
1137                         fprintf(stderr, "%s: ACE alloc error %d\n", __func__,
1138                                 errno);
1139                         goto build_cmdline_aces_ret;
1140                 }
1141
1142                 if (setcifsacl_str_to_sid(acesid, &cacesptr[i]->sid)) {
1143                         fprintf(stderr, "%s: Invalid SID (%s): %s\n", __func__,
1144                                 arrptr[i], plugin_errmsg);
1145                         goto build_cmdline_aces_ret;
1146                 }
1147
1148                 if (verify_ace_type(acetype, &cacesptr[i]->type, ace_kind)) {
1149                         fprintf(stderr, "%s: Invalid ACE type: %s\n",
1150                                         __func__, arrptr[i]);
1151                         goto build_cmdline_aces_ret;
1152                 }
1153
1154                 if (verify_ace_flags(aceflag, &cacesptr[i]->flags, ace_kind)) {
1155                         fprintf(stderr, "%s: Invalid ACE flag: %s\n",
1156                                 __func__, arrptr[i]);
1157                         goto build_cmdline_aces_ret;
1158                 }
1159
1160                 if (verify_ace_mask(acemask, &access_req)) {
1161                         fprintf(stderr, "%s: Invalid ACE mask: %s\n",
1162                                 __func__, arrptr[i]);
1163                         goto build_cmdline_aces_ret;
1164                 }
1165
1166                 cacesptr[i]->access_req = access_req;
1167
1168                 cacesptr[i]->size = htole16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
1169                                             cacesptr[i]->sid.num_subauth * 4);
1170         }
1171         return cacesptr;
1172
1173 build_cmdline_aces_ret:
1174         for (i = 0; i < numcaces; ++i)
1175                 free(cacesptr[i]);
1176         free(cacesptr);
1177         return NULL;
1178 }
1179
1180 static char **
1181 parse_cmdline_aces(char *acelist, int numcaces)
1182 {
1183         int i = 0;
1184         char *acestr, *vacestr, **arrptr = NULL;
1185
1186         arrptr = (char **)malloc(numcaces * sizeof(char *));
1187         if (!arrptr) {
1188                 fprintf(stderr, "%s: Unable to allocate char array\n",
1189                         __func__);
1190                 return NULL;
1191         }
1192
1193         while (i < numcaces) {
1194                 acestr = strtok(acelist, ","); /* everything before , */
1195                 if (!acestr)
1196                         goto parse_cmdline_aces_err;
1197
1198                 vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
1199                 if (!vacestr)
1200                         goto parse_cmdline_aces_err;
1201                 vacestr += 4; /* skip past "ACL:" */
1202                 if (*vacestr) {
1203                         arrptr[i] = vacestr;
1204                         ++i;
1205                 }
1206                 acelist = NULL;
1207         }
1208         return arrptr;
1209
1210 parse_cmdline_aces_err:
1211         fprintf(stderr, "%s: Error parsing ACEs\n", __func__);
1212         free(arrptr);
1213         return NULL;
1214 }
1215
1216 /* How many aces were provided on the command-line? Count the commas. */
1217 static unsigned int
1218 get_numcaces(const char *aces)
1219 {
1220         unsigned int num = 1;
1221         const char *current;
1222
1223         current = aces;
1224         while((current = strchr(current, ','))) {
1225                 ++current;
1226                 ++num;
1227         }
1228
1229         return num;
1230 }
1231
1232 static int
1233 setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
1234                 ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
1235                 struct cifs_ace **cacesptr, int numcaces,
1236                 enum setcifsacl_actions maction, ace_kinds ace_kind)
1237 {
1238         int rc = 1;
1239
1240         switch (maction) {
1241         case ActDelete:
1242                 rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
1243                                 numfaces, cacesptr, numcaces, ace_kind);
1244                 break;
1245         case ActModify:
1246                 rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
1247                                 numfaces, cacesptr, numcaces, ace_kind);
1248                 break;
1249         case ActAdd:
1250                 rc = ace_add(pntsd, npntsd, bufsize, facesptr,
1251                                 numfaces, cacesptr, numcaces, ace_kind);
1252                 break;
1253         case ActSetAcl:
1254                 rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces,
1255                                 ace_kind);
1256                 break;
1257         case ActAddReorder:
1258                 rc = ace_add_reorder(pntsd, npntsd, bufsize, facesptr,
1259                                 numfaces, cacesptr, numcaces, ace_kind);
1260                 break;
1261         default:
1262                 fprintf(stderr, "%s: Invalid action: %d\n", __func__, maction);
1263                 break;
1264         }
1265
1266         return rc;
1267 }
1268
1269 static void
1270 setcifsacl_usage(const char *prog)
1271 {
1272         fprintf(stderr,
1273         "%s: Alter components of CIFS/NTFS security descriptor of a file object\n",
1274                 prog);
1275         fprintf(stderr, "Usage: %s option [<list_of_ACEs>|<SID>] <file_name>\n",
1276                 prog);
1277         fprintf(stderr, "Valid options:\n");
1278         fprintf(stderr, "\t-v   Version of the program\n");
1279         fprintf(stderr, "\t-U   Used in combination with -a, -D, -M, -S in order to ");
1280         fprintf(stderr, "\n\t   apply the actions to SALC (aUdit ACL); if not specified, ");
1281         fprintf(stderr, "\n\t   the actions apply to DACL\n");
1282         fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
1283         fprintf(stderr,
1284         "\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
1285         fprintf(stderr, "\n");
1286         fprintf(stderr, "\t-A   Add ACE(s) and reorder, separated by a comma, to an ACL\n");
1287         fprintf(stderr,
1288         "\tsetcifsacl -A \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
1289         fprintf(stderr, "\n");
1290         fprintf(stderr,
1291         "\t-D   Delete ACE(s), separated by a comma, from an ACL\n");
1292         fprintf(stderr,
1293         "\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
1294         fprintf(stderr, "\n");
1295         fprintf(stderr,
1296         "\t-M   Modify ACE(s), separated by a comma, in an ACL\n");
1297         fprintf(stderr,
1298         "\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
1299         fprintf(stderr,
1300         "\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
1301         fprintf(stderr,
1302         "\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
1303         fprintf(stderr,
1304         "\n\t-o Set owner using specified SID (name or raw format)\n");
1305         fprintf(stderr,
1306         "\tsetcifsacl -o \"Administrator\" <file_name>\n");
1307         fprintf(stderr,
1308         "\n\t-g Set group using specified SID (name or raw format)\n");
1309         fprintf(stderr,
1310         "\tsetcifsacl -g \"Administrators\" <file_name>\n");
1311         fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
1312 }
1313
1314 int
1315 main(const int argc, char *const argv[])
1316 {
1317         int i, rc, c, numcaces = 0, numfaces = 0;
1318         enum setcifsacl_actions maction = ActUnknown;
1319         ssize_t attrlen, bufsize = BUFSIZE;
1320         char *ace_list = NULL, *filename = NULL, *attrval = NULL,
1321                 **arrptr = NULL, *sid_str = NULL;
1322         struct cifs_ctrl_acl *aclptr = NULL;
1323         struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
1324         struct cifs_ntsd *ntsdptr = NULL;
1325         struct cifs_sid sid;
1326         char *attrname = ATTRNAME_ACL;
1327         ace_kinds ace_kind = ACE_KIND_DACL;
1328
1329         while ((c = getopt(argc, argv, "hvD:M:a:A:S:o:g:U")) != -1) {
1330                 switch (c) {
1331                 case 'U':
1332                         ace_kind = ACE_KIND_SACL;
1333                         attrname = ATTRNAME_NTSD_FULL;
1334                         break;
1335                 case 'D':
1336                         maction = ActDelete;
1337                         ace_list = optarg;
1338                         break;
1339                 case 'M':
1340                         maction = ActModify;
1341                         ace_list = optarg;
1342                         break;
1343                 case 'a':
1344                         maction = ActAdd;
1345                         ace_list = optarg;
1346                         break;
1347                 case 'A':
1348                         maction = ActAddReorder;
1349                         ace_list = optarg;
1350                         break;
1351                 case 'S':
1352                         maction = ActSetAcl;
1353                         ace_list = optarg;
1354                         break;
1355                 case 'o':
1356                         maction = ActSetOwner;
1357                         sid_str = optarg;
1358                         attrname = ATTRNAME_NTSD;
1359                         break;
1360                 case 'g':
1361                         maction = ActSetGroup;
1362                         sid_str = optarg;
1363                         attrname = ATTRNAME_NTSD;
1364                         break;
1365                 case 'h':
1366                         setcifsacl_usage(basename(argv[0]));
1367                         return 0;
1368                 case 'v':
1369                         printf("Version: %s\n", VERSION);
1370                         return 0;
1371                 default:
1372                         setcifsacl_usage(basename(argv[0]));
1373                         return -1;
1374                 }
1375         }
1376
1377         /* We expect 1 required and one optional argument in addition to the option */
1378         if (argc < 4 || argc > 5) {
1379                 setcifsacl_usage(basename(argv[0]));
1380                 return -1;
1381         }
1382         filename = argv[argc-1];
1383
1384         if (!ace_list && maction != ActSetOwner && maction != ActSetGroup) {
1385                 fprintf(stderr, "%s: No valid ACEs specified\n", __func__);
1386                 return -1;
1387         }
1388
1389         if (!sid_str && (maction == ActSetOwner || maction == ActSetGroup)) {
1390                 fprintf(stderr, "%s: No valid SIDs specified\n", __func__);
1391                 return -1;
1392         }
1393
1394         if (init_plugin(&plugin_handle)) {
1395                 fprintf(stderr, "WARNING: unable to initialize idmapping "
1396                                 "plugin. Only \"raw\" SID strings will be "
1397                                 "accepted: %s\n", plugin_errmsg);
1398                 plugin_loaded = false;
1399         } else {
1400                 plugin_loaded = true;
1401         }
1402
1403         if (maction == ActSetOwner || maction == ActSetGroup) {
1404                 if (ace_kind == ACE_KIND_SACL) {
1405                         fprintf(stderr, "WARNING: disregarding -U when setting"
1406                                         " owner/group\n");
1407                         ace_kind = ACE_KIND_DACL;
1408                 }
1409                 /* parse the sid */
1410                 if (setcifsacl_str_to_sid(sid_str, &sid)) {
1411                         fprintf(stderr, "%s: failed to parce \'%s\' as SID\n",
1412                                 __func__, sid_str);
1413                         goto setcifsacl_numcaces_ret;
1414                 }
1415         } else {
1416                 numcaces = get_numcaces(ace_list);
1417
1418                 arrptr = parse_cmdline_aces(ace_list, numcaces);
1419                 if (!arrptr)
1420                         goto setcifsacl_numcaces_ret;
1421
1422                 cacesptr = build_cmdline_aces(arrptr, numcaces, ace_kind);
1423                 if (!cacesptr)
1424                         goto setcifsacl_cmdlineparse_ret;
1425         }
1426 cifsacl:
1427         if (bufsize >= XATTR_SIZE_MAX) {
1428                 fprintf(stderr, "%s: Buffer size %zd exceeds max size of %d\n",
1429                                 __func__, bufsize, XATTR_SIZE_MAX);
1430                 goto setcifsacl_cmdlineverify_ret;
1431         }
1432
1433         attrval = malloc(bufsize * sizeof(char));
1434         if (!attrval) {
1435                 fprintf(stderr, "error allocating memory for attribute value "
1436                         "buffer\n");
1437                 goto setcifsacl_cmdlineverify_ret;
1438         }
1439
1440         attrlen = getxattr(filename, attrname, attrval, bufsize);
1441         if (attrlen == -1) {
1442                 if (errno == ERANGE) {
1443                         free(attrval);
1444                         bufsize += BUFSIZE;
1445                         goto cifsacl;
1446                 } else {
1447                         fprintf(stderr, "getxattr error: %d\n", errno);
1448                         goto setcifsacl_getx_ret;
1449                 }
1450         }
1451
1452         if (maction == ActSetOwner || maction == ActSetGroup) {
1453                 struct cifs_ntsd *pfntsd = (struct cifs_ntsd *)attrval;
1454                 int dacloffset = le32toh(pfntsd->dacloffset);
1455                 struct cifs_ctrl_acl *daclinfo;
1456                 int numaces, acessize;
1457                 size_t faceoffset, naceoffset;
1458                 char *faceptr, *naceptr;
1459                 /*
1460                  * dacloffset of 0 means "no DACL - all access for everyone"
1461                  * if dacloffset is not 0, it is still possible that DACL is
1462                  * empty - numaces is zero - "no access for anyone"
1463                  */
1464                 if (dacloffset) {
1465                         daclinfo = (struct cifs_ctrl_acl *)(attrval + dacloffset);
1466                         numaces = le16toh(daclinfo->num_aces);
1467                         acessize = le32toh(daclinfo->size);
1468                 } else {
1469                         daclinfo = NULL;
1470                         numaces = 0;
1471                         acessize = 0;
1472                 }
1473                 /*
1474                  * this allocates large enough buffer for max sid size and the
1475                  * dacl info from the fetched security descriptor
1476                  */
1477                 rc = alloc_sec_desc(pfntsd, &ntsdptr, numaces, &faceoffset,
1478                                 ACE_KIND_DACL);
1479                 if (rc)
1480                         goto setcifsacl_numcaces_ret;
1481
1482                 /*
1483                  * copy the control structures from the fetched descriptor, the
1484                  * sid specified by the user, and adjust the offsets/move dacl
1485                  * control structure if needed
1486                  */
1487                 bufsize = copy_sec_desc_with_sid(pfntsd, ntsdptr, &sid,
1488                                 maction);
1489
1490                 /* copy DACL aces verbatim as they have not changed */
1491                 if (dacloffset) {
1492                         faceptr = attrval + faceoffset;
1493                         naceoffset = le32toh(ntsdptr->dacloffset) +
1494                                 sizeof(struct cifs_ctrl_acl);
1495                         naceptr = (char *)ntsdptr + naceoffset;
1496                         memcpy(naceptr, faceptr, acessize);
1497                 }
1498         } else {
1499                 bufsize = 0;
1500
1501                 numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen,
1502                                 &aclptr, ace_kind);
1503                 if (!numfaces && (maction != ActAdd && maction != ActAddReorder)) {
1504                         /* if we are not adding aces */
1505                         fprintf(stderr, "%s: Empty DACL\n", __func__);
1506                         goto setcifsacl_facenum_ret;
1507                 }
1508
1509                 facesptr = build_fetched_aces((char *)aclptr, numfaces);
1510                 if (!facesptr)
1511                         goto setcifsacl_facenum_ret;
1512
1513                 rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr,
1514                                 &bufsize, facesptr, numfaces, cacesptr,
1515                                 numcaces, maction, ace_kind);
1516                 if (rc)
1517                         goto setcifsacl_action_ret;
1518         }
1519
1520         attrlen = setxattr(filename, attrname, ntsdptr, bufsize, 0);
1521         if (attrlen == -1) {
1522                 fprintf(stderr, "%s: setxattr error: %s\n", __func__,
1523                         strerror(errno));
1524                 goto setcifsacl_action_ret;
1525         }
1526
1527         if (plugin_loaded)
1528                 exit_plugin(plugin_handle);
1529         return 0;
1530
1531 setcifsacl_action_ret:
1532         if (ntsdptr)
1533                 free(ntsdptr);
1534
1535 setcifsacl_facenum_ret:
1536         if (facesptr) {
1537                 for (i = 0; i < numfaces; ++i)
1538                         free(facesptr[i]);
1539                 free(facesptr);
1540         }
1541
1542 setcifsacl_getx_ret:
1543         if (attrval)
1544                 free(attrval);
1545
1546 setcifsacl_cmdlineverify_ret:
1547         if (cacesptr) {
1548                 for (i = 0; i < numcaces; ++i)
1549                         free(cacesptr[i]);
1550                 free(cacesptr);
1551         }
1552
1553 setcifsacl_cmdlineparse_ret:
1554         if (arrptr)
1555                 free(arrptr);
1556
1557 setcifsacl_numcaces_ret:
1558         if (plugin_loaded)
1559                 exit_plugin(plugin_handle);
1560         return -1;
1561 }