setcifsacl: fix endianness of ->size in build_cmdline_aces
[jlayton/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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* HAVE_CONFIG_H */
26
27 #include <string.h>
28 #include <getopt.h>
29 #include <syslog.h>
30 #include <stdint.h>
31 #include <stdbool.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <wbclient.h>
38 #include <ctype.h>
39 #include <sys/xattr.h>
40 #include "cifsacl.h"
41
42 static const char *prog;
43
44 enum setcifsacl_actions {
45         ActUnknown = -1,
46         ActDelete,
47         ActModify,
48         ActAdd,
49         ActSet
50 };
51
52 static void
53 copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
54 {
55         int i;
56
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];
63 }
64
65 static void
66 copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
67                 int numaces, int acessize)
68 {
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;
73
74         /* copy security descriptor control portion */
75         osidsoffset = le32toh(pntsd->osidoffset);
76         gsidsoffset = le32toh(pntsd->gsidoffset);
77         dacloffset = le32toh(pntsd->dacloffset);
78
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;
84
85         dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
86         ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
87
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);
91
92         /* copy owner sid */
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);
96
97         /* copy group sid */
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);
101
102         return;
103 }
104
105 static int
106 copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
107 {
108         dace->type = sace->type;
109         dace->flags = sace->flags;
110         dace->access_req = sace->access_req;
111
112         copy_cifs_sid(&dace->sid, &sace->sid);
113
114         dace->size = sace->size;
115
116         return le16toh(dace->size);
117 }
118
119 static int
120 compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
121 {
122         int i;
123
124         if (compflags & COMPSID) {
125                 if (dace->sid.revision != sace->sid.revision)
126                         return 0;
127                 if (dace->sid.num_subauth != sace->sid.num_subauth)
128                         return 0;
129                 for (i = 0; i < NUM_AUTHS; i++) {
130                         if (dace->sid.authority[i] != sace->sid.authority[i])
131                                 return 0;
132                 }
133                 for (i = 0; i < sace->sid.num_subauth; i++) {
134                         if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
135                                 return 0;
136                 }
137         }
138
139         if (compflags & COMPTYPE) {
140                 if (dace->type != sace->type)
141                         return 0;
142         }
143
144         if (compflags & COMPFLAG) {
145                 if (dace->flags != sace->flags)
146                         return 0;
147         }
148
149         if (compflags & COMPMASK) {
150                 if (dace->access_req != sace->access_req)
151                         return 0;
152         }
153
154         return 1;
155 }
156
157 static int
158 get_sec_desc_size(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
159                         int aces, ssize_t *bufsize, size_t *acesoffset)
160 {
161         unsigned int size, acessize, dacloffset;
162
163         size = sizeof(struct cifs_ntsd) +
164                 2 * sizeof(struct cifs_sid) +
165                 sizeof(struct cifs_ctrl_acl);
166
167         dacloffset = le32toh(pntsd->dacloffset);
168
169         *acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
170         acessize = aces * sizeof(struct cifs_ace);
171         *bufsize = size + acessize;
172
173         *npntsd = malloc(*bufsize);
174         if (!*npntsd) {
175                 printf("%s: Memory allocation failure", __func__);
176                 return errno;
177         }
178
179         return 0;
180 }
181
182 static int
183 ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
184                         struct cifs_ace **cacesptr, int numcaces)
185 {
186         int i, rc, acessize = 0;
187         size_t acesoffset;
188         char *acesptr;
189
190         rc = get_sec_desc_size(pntsd, npntsd, numcaces, bufsize, &acesoffset);
191         if (rc)
192                 return rc;
193
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);
198         }
199         copy_sec_desc(pntsd, *npntsd, numcaces, acessize);
200         acesptr = (char *)*npntsd + acesoffset;
201
202
203         return 0;
204 }
205
206 static int
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)
210 {
211         int i, rc, numaces, size, acessize = 0;
212         size_t acesoffset;
213         char *acesptr;
214
215         numaces = numfaces + numcaces;
216         rc = get_sec_desc_size(pntsd, npntsd, numaces, bufsize, &acesoffset);
217         if (rc)
218                 return rc;
219
220         acesptr = (char *)*npntsd + acesoffset;
221         for (i = 0; i < numfaces; ++i) {
222                 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
223                 acesptr += size;
224                 acessize += size;
225         }
226         for (i = 0; i < numcaces; ++i) {
227                 size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
228                 acesptr += size;
229                 acessize += size;
230         }
231         copy_sec_desc(pntsd, *npntsd, numaces, acessize);
232
233         return 0;
234 }
235
236 static int
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)
240 {
241         int i, j, rc, size, acessize = 0;
242         size_t acesoffset;
243         char *acesptr;
244
245         if (numfaces == 0) {
246                 printf("%s: No entries to modify", __func__);
247                 return -1;
248         }
249
250         rc = get_sec_desc_size(pntsd, npntsd, numfaces, bufsize, &acesoffset);
251         if (rc)
252                 return rc;
253
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]);
259                                 break;
260                         }
261                 }
262         }
263
264         acesptr = (char *)*npntsd + acesoffset;
265         for (i = 0; i < numfaces; ++i) {
266                 size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
267                 acesptr += size;
268                 acessize += size;
269         }
270
271         copy_sec_desc(pntsd, *npntsd, numfaces, acessize);
272
273         return 0;
274 }
275
276 static int
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)
280 {
281         int i, j, numaces = 0, rc, size, acessize = 0;
282         size_t acesoffset;
283         char *acesptr;
284
285         if (numfaces == 0) {
286                 printf("%s: No entries to delete\n", __func__);
287                 return -1;
288         }
289
290         if (numfaces < numcaces) {
291                 printf("%s: Invalid entries to delete\n", __func__);
292                 return -1;
293         }
294
295         rc = get_sec_desc_size(pntsd, npntsd, numfaces, bufsize, &acesoffset);
296         if (rc)
297                 return rc;
298
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))
303                                 break;
304                 }
305                 if (j == numcaces) {
306                         size = copy_ace((struct cifs_ace *)acesptr,
307                                                                 facesptr[i]);
308                         acessize += size;
309                         acesptr += size;
310                         ++numaces;
311                 }
312         }
313
314         if (numaces == numfaces) {
315                 printf("%s: Nothing to delete\n", __func__);
316                 return 1;
317         }
318         copy_sec_desc(pntsd, *npntsd, numaces, acessize);
319
320         return 0;
321 }
322
323 static int
324 get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
325                         struct cifs_ctrl_acl **daclptr)
326 {
327         int numfaces = 0;
328         uint32_t dacloffset;
329         struct cifs_ctrl_acl *ldaclptr;
330         char *end_of_acl = ((char *)pntsd) + acl_len;
331
332         dacloffset = le32toh(pntsd->dacloffset);
333         if (!dacloffset)
334                 return 0;
335
336         ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
337
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);
341                 *daclptr = ldaclptr;
342         }
343
344         return numfaces;
345 }
346
347 static struct cifs_ace **
348 build_fetched_aces(char *daclptr, int numfaces)
349 {
350         int i, acl_size;
351         char *acl_base;
352         struct cifs_ace *pace, **facesptr;
353
354         facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
355         if (!facesptr) {
356                 printf("%s: Error %d allocating ACE array",
357                                 __func__, errno);
358                 return facesptr;
359         }
360
361         acl_base = daclptr;
362         acl_size = sizeof(struct cifs_ctrl_acl);
363         for (i = 0; i < numfaces; ++i) {
364                 facesptr[i] = malloc(sizeof(struct cifs_ace));
365                 if (!facesptr[i])
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);
371         }
372         return facesptr;
373
374 build_fetched_aces_err:
375         printf("%s: Invalid fetched ace\n", __func__);
376         for (i = 0; i < numfaces; ++i)
377                 free(facesptr[i]);
378         free(facesptr);
379         return NULL;
380 }
381
382 static int
383 verify_ace_sid(char *sidstr, struct cifs_sid *sid)
384 {
385         int i;
386         wbcErr rc;
387         char *name, *domain;
388         enum wbcSidType type;
389
390         name = strchr(sidstr, '\\');
391         if (!name) {
392                 /* might be a raw string representation of SID */
393                 rc = wbcStringToSid(sidstr, (struct wbcDomainSid *)sid);
394                 if (WBC_ERROR_IS_OK(rc))
395                         goto fix_endianness;
396
397                 domain = "";
398                 name = sidstr;
399         } else {
400                 domain = sidstr;
401                 *name = '\0';
402                 ++name;
403         }
404
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));
409                 return rc;
410         }
411
412 fix_endianness:
413         /*
414          * Winbind keeps wbcDomainSid fields in host-endian. So, we must
415          * convert that to little endian since the server will expect that.
416          */
417         for (i = 0; i < sid->num_subauth; i++)
418                 sid->sub_auth[i] = htole32(sid->sub_auth[i]);
419         return 0;
420 }
421
422 static int
423 verify_ace_type(char *typestr, uint8_t *typeval)
424 {
425         int i, len;
426         char *invaltype;
427
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",
436                                                 __func__, typestr);
437                                         return 1;
438                         }
439                         return 0;
440                 }
441         }
442
443         len = strlen(typestr);
444         for (i = 0; i < len; ++i)
445                 *(typestr + i) = toupper(*(typestr + i));
446         if (!strcmp(typestr, "ALLOWED"))
447                 *typeval = 0x0;
448         else if (!strcmp(typestr, "DENIED"))
449                 *typeval = 0x1;
450         else if (!strcmp(typestr, "ALLOWED_OBJECT"))
451                 *typeval = 0x5;
452         else if (!strcmp(typestr, "DENIED_OBJECT"))
453                 *typeval = 0x6;
454         else {
455                 printf("%s: Invalid type: %s\n", __func__, typestr);
456                 return 1;
457         }
458
459         return 0;
460 }
461
462 static uint8_t
463 ace_flag_value(char *flagstr)
464 {
465         uint8_t flagval = 0x0;
466         char *iflag;
467
468         iflag = strtok(flagstr, "|"); /* everything before | */
469         while (iflag) {
470                 if (!strcmp(iflag, "OI"))
471                         flagval += 0x1;
472                 else if (!strcmp(iflag, "CI"))
473                         flagval += 0x2;
474                 else if (!strcmp(iflag, "NP"))
475                         flagval += 0x4;
476                 else if (!strcmp(iflag, "IO"))
477                         flagval += 0x8;
478                 else if (!strcmp(iflag, "I"))
479                         flagval += 0x10;
480                 else
481                         return 0x0; /* Invalid flag */
482                 iflag = strtok(NULL, "|"); /* everything before | */
483         }
484
485         return flagval;
486 }
487
488 static int
489 verify_ace_flags(char *flagstr, uint8_t *flagval)
490 {
491         char *invalflag;
492
493         if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
494                 return 0;
495
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);
500                         return 1;
501                 }
502         } else
503                 *flagval = ace_flag_value(flagstr);
504
505         if (!*flagval || (*flagval & ~VFLAGS)) {
506                 printf("%s: Invalid flag %s and value: 0x%x\n",
507                         __func__, flagstr, *flagval);
508                 return 1;
509         }
510
511         return 0;
512 }
513
514 static uint32_t
515 ace_mask_value(char *mask)
516 {
517         uint32_t maskval = 0;
518         char cur;
519
520         if (!strcmp(mask, "FULL"))
521                 return FULL_CONTROL;
522         if (!strcmp(mask, "CHANGE"))
523                 return CHANGE;
524         if (!strcmp(mask, "READ"))
525                 return EREAD;
526
527         while((cur = *mask++)) {
528                 switch(cur) {
529                 case 'R':
530                         maskval |= EREAD;
531                         break;
532                 case 'W':
533                         maskval |= EWRITE;
534                         break;
535                 case 'X':
536                         maskval |= EXEC;
537                         break;
538                 case 'D':
539                         maskval |= DELETE;
540                         break;
541                 case 'P':
542                         maskval |= WRITE_DAC;
543                         break;
544                 case 'O':
545                         maskval |= WRITE_OWNER;
546                         break;
547                 default:
548                         return 0;
549                 }
550         }
551         return maskval;
552 }
553
554 static int
555 verify_ace_mask(char *maskstr, uint32_t *maskval)
556 {
557         unsigned long val;
558         char *ep;
559
560         errno = 0;
561         val = strtoul(maskstr, &ep, 0);
562         if (errno == 0 && *ep == '\0')
563                 *maskval = htole32((uint32_t)val);
564         else
565                 *maskval = htole32(ace_mask_value(maskstr));
566
567         if (!*maskval) {
568                 printf("%s: Invalid mask %s (value 0x%x)\n", __func__,
569                         maskstr, *maskval);
570                 return 1;
571         }
572
573         return 0;
574 }
575
576 static struct cifs_ace **
577 build_cmdline_aces(char **arrptr, int numcaces)
578 {
579         int i;
580         char *acesid, *acetype, *aceflag, *acemask;
581         struct cifs_ace **cacesptr;
582
583         cacesptr = calloc(numcaces, sizeof(struct cifs_aces *));
584         if (!cacesptr) {
585                 printf("%s: Error %d allocating ACE array", __func__, errno);
586                 return NULL;
587         }
588
589         for (i = 0; i < numcaces; ++i) {
590                 acesid = strtok(arrptr[i], ":");
591                 acetype = strtok(NULL, "/");
592                 aceflag = strtok(NULL, "/");
593                 acemask = strtok(NULL, "/");
594
595                 if (!acesid || !acetype || !aceflag || !acemask) {
596                         printf("%s: Incomplete ACE: %s\n", __func__, arrptr[i]);
597                         goto build_cmdline_aces_ret;
598                 }
599
600                 cacesptr[i] = malloc(sizeof(struct cifs_ace));
601                 if (!cacesptr[i]) {
602                         printf("%s: ACE alloc error %d\n", __func__, errno);
603                         goto build_cmdline_aces_ret;
604                 }
605
606                 if (verify_ace_sid(acesid, &cacesptr[i]->sid)) {
607                         printf("%s: Invalid SID: %s\n", __func__, arrptr[i]);
608                         goto build_cmdline_aces_ret;
609                 }
610
611                 if (verify_ace_type(acetype, &cacesptr[i]->type)) {
612                         printf("%s: Invalid ACE type: %s\n",
613                                         __func__, arrptr[i]);
614                         goto build_cmdline_aces_ret;
615                 }
616
617                 if (verify_ace_flags(aceflag, &cacesptr[i]->flags)) {
618                         printf("%s: Invalid ACE flag: %s\n",
619                                 __func__, arrptr[i]);
620                         goto build_cmdline_aces_ret;
621                 }
622
623                 if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
624                         printf("%s: Invalid ACE mask: %s\n",
625                                 __func__, arrptr[i]);
626                         goto build_cmdline_aces_ret;
627                 }
628
629                 cacesptr[i]->size = htole16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
630                                             cacesptr[i]->sid.num_subauth * 4);
631         }
632         return cacesptr;
633
634 build_cmdline_aces_ret:
635         for (i = 0; i < numcaces; ++i)
636                 free(cacesptr[i]);
637         free(cacesptr);
638         return NULL;
639 }
640
641 static char **
642 parse_cmdline_aces(char *acelist, int numcaces)
643 {
644         int i = 0, len;
645         char *acestr, *vacestr, **arrptr = NULL;
646
647         arrptr = (char **)malloc(numcaces * sizeof(char *));
648         if (!arrptr) {
649                 printf("%s: Unable to allocate char array\n", __func__);
650                 return NULL;
651         }
652
653         while (i < numcaces) {
654                 acestr = strtok(acelist, ","); /* everything before , */
655                 if (!acestr)
656                         goto parse_cmdline_aces_err;
657
658                 vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
659                 if (!vacestr)
660                         goto parse_cmdline_aces_err;
661                 vacestr += 4; /* skip past "ACL:" */
662                 if (*vacestr) {
663                         arrptr[i] = vacestr;
664                         ++i;
665                 }
666                 acelist = NULL;
667         }
668         return arrptr;
669
670 parse_cmdline_aces_err:
671         printf("%s: Error parsing ACEs\n", __func__);
672         free(arrptr);
673         return NULL;
674 }
675
676 /* How many aces were provided on the command-line? Count the commas. */
677 static unsigned int
678 get_numcaces(const char *aces)
679 {
680         int i, len;
681         unsigned int num = 1;
682         const char *current;
683
684         current = aces;
685         while((current = strchr(current, ',')))
686                 ++num;
687
688         return num;
689 }
690
691 static int
692 setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
693                 ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
694                 struct cifs_ace **cacesptr, int numcaces,
695                 enum setcifsacl_actions maction)
696 {
697         int rc = 1;
698
699         switch (maction) {
700         case ActDelete:
701                 rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
702                                 numfaces, cacesptr, numcaces);
703                 break;
704         case ActModify:
705                 rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
706                                 numfaces, cacesptr, numcaces);
707                 break;
708         case ActAdd:
709                 rc = ace_add(pntsd, npntsd, bufsize, facesptr,
710                                 numfaces, cacesptr, numcaces);
711                 break;
712         case ActSet:
713                 rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
714                 break;
715         default:
716                 printf("%s: Invalid action: %d\n", __func__, maction);
717                 break;
718         }
719
720         return rc;
721 }
722
723 static void
724 setcifsacl_usage(void)
725 {
726         fprintf(stderr,
727         "%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
728                 prog);
729         fprintf(stderr, "Usage: %s option <list_of_ACEs> <file_name>\n", prog);
730         fprintf(stderr, "Valid options:\n");
731         fprintf(stderr, "\t-v   Version of the program\n");
732         fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
733         fprintf(stderr,
734         "\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
735         fprintf(stderr, "\n");
736         fprintf(stderr,
737         "\t-D   Delete ACE(s), separated by a comma, from an ACL\n");
738         fprintf(stderr,
739         "\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
740         fprintf(stderr, "\n");
741         fprintf(stderr,
742         "\t-M   Modify ACE(s), separated by a comma, in an ACL\n");
743         fprintf(stderr,
744         "\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
745         fprintf(stderr,
746         "\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
747         fprintf(stderr,
748         "\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
749         fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
750 }
751
752 int
753 main(const int argc, char *const argv[])
754 {
755         int i, rc, c, numcaces, numfaces;
756         enum setcifsacl_actions maction = ActUnknown;
757         ssize_t attrlen, bufsize = BUFSIZE;
758         char *ace_list, *filename, *attrval, **arrptr = NULL;
759         struct cifs_ctrl_acl *daclptr = NULL;
760         struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
761         struct cifs_ntsd *ntsdptr = NULL;
762
763         prog = basename(argv[0]);
764
765         openlog(prog, 0, LOG_DAEMON);
766
767         c = getopt(argc, argv, "hvD:M:a:S:");
768         switch (c) {
769         case 'D':
770                 maction = ActDelete;
771                 ace_list = optarg;
772                 break;
773         case 'M':
774                 maction = ActModify;
775                 ace_list = optarg;
776                 break;
777         case 'a':
778                 maction = ActAdd;
779                 ace_list = optarg;
780                 break;
781         case 'S':
782                 maction = ActSet;
783                 ace_list = optarg;
784                 break;
785         case 'h':
786                 setcifsacl_usage();
787                 return 0;
788         case 'v':
789                 printf("Version: %s\n", VERSION);
790                 return 0;
791         default:
792                 setcifsacl_usage();
793                 return -1;
794         }
795
796         /* We expect 1 argument in addition to the option */
797         if (argc != 4) {
798                 setcifsacl_usage();
799                 return -1;
800         }
801         filename = argv[3];
802
803         if (!ace_list) {
804                 printf("%s: No valid ACEs specified\n", __func__);
805                 return -1;
806         }
807
808         numcaces = get_numcaces(ace_list);
809
810         arrptr = parse_cmdline_aces(ace_list, numcaces);
811         if (!arrptr)
812                 goto setcifsacl_numcaces_ret;
813
814         cacesptr = build_cmdline_aces(arrptr, numcaces);
815         if (!cacesptr)
816                 goto setcifsacl_cmdlineparse_ret;
817
818 cifsacl:
819         if (bufsize >= XATTR_SIZE_MAX) {
820                 printf("%s: Buffer size %ld exceeds max size of %d\n",
821                                 __func__, bufsize, XATTR_SIZE_MAX);
822                 goto setcifsacl_cmdlineverify_ret;
823         }
824
825         attrval = malloc(bufsize * sizeof(char));
826         if (!attrval) {
827                 printf("error allocating memory for attribute value buffer\n");
828                 goto setcifsacl_cmdlineverify_ret;
829         }
830
831         attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
832         if (attrlen == -1) {
833                 if (errno == ERANGE) {
834                         free(attrval);
835                         bufsize += BUFSIZE;
836                         goto cifsacl;
837                 } else {
838                         printf("getxattr error: %d\n", errno);
839                         goto setcifsacl_getx_ret;
840                 }
841         }
842
843         numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
844         if (!numfaces && maction != ActAdd) { /* if we are not adding aces */
845                 printf("%s: Empty DACL\n", __func__);
846                 goto setcifsacl_facenum_ret;
847         }
848
849         facesptr = build_fetched_aces((char *)daclptr, numfaces);
850         if (!facesptr)
851                 goto setcifsacl_facenum_ret;
852
853         bufsize = 0;
854         rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
855                 facesptr, numfaces, cacesptr, numcaces, maction);
856         if (rc)
857                 goto setcifsacl_action_ret;
858
859         attrlen = setxattr(filename, ATTRNAME, ntsdptr, bufsize, 0);
860         if (attrlen == -1)
861                 printf("%s: setxattr error: %s\n", __func__, strerror(errno));
862         goto setcifsacl_facenum_ret;
863
864         return 0;
865
866 setcifsacl_action_ret:
867         free(ntsdptr);
868
869 setcifsacl_facenum_ret:
870         for (i = 0; i < numfaces; ++i)
871                 free(facesptr[i]);
872         free(facesptr);
873
874 setcifsacl_getx_ret:
875         free(attrval);
876
877 setcifsacl_cmdlineverify_ret:
878         for (i = 0; i < numcaces; ++i)
879                 free(cacesptr[i]);
880         free(cacesptr);
881
882 setcifsacl_cmdlineparse_ret:
883         free(arrptr);
884
885 setcifsacl_numcaces_ret:
886         return -1;
887 }