4 * Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
6 * Used to display a security descriptor including ACL of a file object
7 * that belongs to a share mounted using option cifsacl.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #endif /* HAVE_CONFIG_H */
37 #include <sys/xattr.h>
39 #include "idmap_plugin.h"
42 static void *plugin_handle;
43 static bool plugin_loaded;
44 static char *execname;
45 static bool raw = false;
48 print_each_ace_mask(uint32_t mask)
50 if ((mask & ALL_ACCESS_BITS) == ALL_ACCESS_BITS) {
55 if ((mask & ALL_READ_BITS) && ((mask & EREAD) != EREAD &&
56 (mask & OREAD) != OREAD && (mask & BREAD) != BREAD)) {
61 if ((mask & ALL_WRITE_BITS) && (mask & EWRITE) != EWRITE) {
66 if ((mask & EREAD) == EREAD || (mask & OREAD) == OREAD ||
67 (mask & BREAD) == BREAD)
69 if ((mask & EWRITE) == EWRITE)
71 if ((mask & EXEC) == EXEC)
73 if ((mask & DELETE) == DELETE)
75 if ((mask & WRITE_DAC) == WRITE_DAC)
77 if ((mask & WRITE_OWNER) == WRITE_OWNER)
82 print_ace_mask(uint32_t mask, int raw, ace_kinds ace_kind)
85 printf("0x%x\n", mask);
91 if (mask == FULL_CONTROL)
93 else if (mask == CHANGE)
95 else if (mask == DELETE)
97 else if (mask == EREAD)
100 print_each_ace_mask(mask);
104 if (mask == FULL_CONTROL)
106 else if (mask == CHANGE)
108 else if (mask == DELETE)
110 else if (mask == EREAD)
112 else if (mask & DELDHLD)
113 printf("0x%x", mask);
115 print_each_ace_mask(mask);
123 print_ace_flags(uint8_t flags, int raw, ace_kinds ace_kind)
128 printf("0x%x", flags);
134 if (flags & SUCCESSFUL_ACCESS) {
138 if (flags & FAILED_ACCESS) {
147 if (flags & OBJECT_INHERIT_FLAG) {
151 if (flags & CONTAINER_INHERIT_FLAG) {
158 if (flags & NO_PROPAGATE_INHERIT_FLAG) {
165 if (flags & INHERIT_ONLY_FLAG) {
172 if (flags & INHERITED_ACE_FLAG) {
187 print_ace_type(uint8_t acetype, int raw)
190 printf("0x%x", acetype);
201 case ACCESS_ALLOWED_OBJECT:
202 printf("OBJECT_ALLOWED");
204 case ACCESS_DENIED_OBJECT:
205 printf("OBJECT_DENIED");
210 case SYSTEM_AUDIT_OBJECT:
211 printf("AUDIT_OBJECT");
213 case SYSTEM_AUDIT_CALLBACK:
214 printf("AUDIT_CALLBACK");
216 case SYSTEM_AUDIT_CALLBACK_OBJECT:
217 printf("AUDIT_CALLBACK_OBJECT");
219 case SYSTEM_MANDATORY_LABEL:
220 printf("MANDATORY_LABEL");
222 case SYSTEM_RESOURCE_ATTRIBUTE:
223 printf("RESOURCE_ATTRIBUTE");
225 case SYSTEM_SCOPED_POLICY_ID:
226 printf("SCOPED_POLICY_ID");
235 print_sid(struct cifs_sid *csid, int raw)
239 unsigned long long id_auth_val;
241 if (raw || !plugin_loaded)
244 rc = sid_to_str(plugin_handle, csid, &name);
253 printf("S-%hhu", csid->revision);
255 id_auth_val = (unsigned long long)csid->authority[5];
256 id_auth_val += (unsigned long long)csid->authority[4] << 8;
257 id_auth_val += (unsigned long long)csid->authority[3] << 16;
258 id_auth_val += (unsigned long long)csid->authority[2] << 24;
259 id_auth_val += (unsigned long long)csid->authority[1] << 32;
260 id_auth_val += (unsigned long long)csid->authority[0] << 40;
263 * MS-DTYP states that if the authority is >= 2^32, then it should be
264 * expressed as a hex value.
266 if (id_auth_val <= UINT_MAX)
267 printf("-%llu", id_auth_val);
269 printf("-0x%llx", id_auth_val);
271 for (i = 0; i < csid->num_subauth; i++)
272 printf("-%u", le32toh(csid->sub_auth[i]));
276 print_ace(struct cifs_ace *pace, char *end_of_acl, int raw, ace_kinds ace_kind)
280 /* make sure we can safely get to "size" */
281 if (end_of_acl < (char *)pace + offsetof(struct cifs_ace, size) + 1)
284 size = le16toh(pace->size);
286 /* 16 == size of cifs_ace when cifs_sid has no subauths */
290 /* validate that we do not go past end of acl */
291 if (end_of_acl < (char *)pace + size)
295 print_sid((struct cifs_sid *)&pace->sid, raw);
297 print_ace_type(pace->type, raw);
299 print_ace_flags(pace->flags, raw, ace_kind);
301 print_ace_mask(le32toh(pace->access_req), raw, ace_kind);
307 parse_acl(struct cifs_ctrl_acl *pacl, char *end_of_acl, int raw, ace_kinds ace_kind)
313 struct cifs_ace *pace;
318 if (end_of_acl < (char *)pacl + le16toh(pacl->size))
321 acl_base = (char *)pacl;
322 acl_size = sizeof(struct cifs_ctrl_acl);
324 num_aces = le32toh(pacl->num_aces);
326 for (i = 0; i < num_aces; ++i) {
327 pace = (struct cifs_ace *) (acl_base + acl_size);
328 print_ace(pace, end_of_acl, raw, ace_kind);
329 acl_base = (char *)pace;
330 acl_size = le16toh(pace->size);
338 parse_sid(struct cifs_sid *psid, char *end_of_acl, char *title, int raw)
340 if (end_of_acl < (char *)psid + 8)
344 printf("%s:", title);
345 print_sid((struct cifs_sid *)psid, raw);
352 parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
355 uint32_t dacloffset, sacloffset;
356 char *end_of_acl = ((char *)pntsd) + acl_len;
357 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
358 struct cifs_ctrl_acl *dacl_ptr, *sacl_ptr;
363 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
364 le32toh(pntsd->osidoffset));
365 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
366 le32toh(pntsd->gsidoffset));
367 dacloffset = le32toh(pntsd->dacloffset);
368 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
369 sacloffset = le32toh(pntsd->sacloffset);
370 sacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + sacloffset);
372 printf("REVISION:0x%x\n", le16toh(pntsd->revision));
373 printf("CONTROL:0x%x\n", le16toh(pntsd->type));
375 rc = parse_sid(owner_sid_ptr, end_of_acl, "OWNER", raw);
379 rc = parse_sid(group_sid_ptr, end_of_acl, "GROUP", raw);
385 parse_acl(dacl_ptr, end_of_acl, raw, ACE_KIND_DACL);
387 printf("No DACL\n"); /* BB grant all or default perms? */
392 parse_acl(sacl_ptr, end_of_acl, raw, ACE_KIND_SACL);
401 getcifsacl_usage(const char *prog)
404 "%s: Display CIFS/NTFS ACL in a security descriptor of a file object\n",
406 fprintf(stderr, "Usage: %s [option] <file_name1> [<file_name2>,<file_name3>,...]\n", prog);
407 fprintf(stderr, "Valid options:\n");
408 fprintf(stderr, "\t-h Display this help text\n");
409 fprintf(stderr, "\n");
410 fprintf(stderr, "\t-v Version of the program\n");
411 fprintf(stderr, "\n");
412 fprintf(stderr, "\t-R recurse into subdirectories\n");
413 fprintf(stderr, "\n");
414 fprintf(stderr, "\t-r Display raw values of the ACE fields\n");
415 fprintf(stderr, "\nRefer to getcifsacl(1) manpage for details\n");
419 getcifsacl(const char *filename)
422 size_t bufsize = BUFSIZE;
425 /* use attribute name to fetch the whole descriptor */
426 char *attrname = ATTRNAME_NTSD_FULL;
429 if (bufsize >= XATTR_SIZE_MAX) {
430 fprintf(stderr, "buffer to allocate exceeds max size of %d\n",
435 attrval = malloc(bufsize * sizeof(char));
437 fprintf(stderr, "error allocating memory for attribute value buffer\n");
442 attrlen = getxattr(filename, attrname, attrval, bufsize);
444 if (errno == ERANGE) {
448 } else if (errno == EIO && !(strcmp(attrname, ATTRNAME_NTSD_FULL))) {
450 * attempt to fetch SACL in addition to owner and DACL via
451 * ATTRNAME_NTSD_FULL, fall back to owner/DACL via
452 * ATTRNAME_ACL if not allowed
453 * CIFS client maps STATUS_PRIVILEGE_NOT_HELD to EIO
455 fprintf(stderr, "WARNING: Insufficient priviledges to fetch SACL for %s\n",
457 fprintf(stderr, " Fetching owner info and DACL only\n");
458 attrname = ATTRNAME_ACL;
460 } else if (errno == EOPNOTSUPP && !(strcmp(attrname, ATTRNAME_NTSD_FULL))) {
462 * no support for fetching SACL, fall back to owner/DACL via
465 fprintf(stderr, "WARNING: CIFS client does not support fetching SACL for %s\n",
467 fprintf(stderr, " Fetching owner info and DACL only\n");
468 attrname = ATTRNAME_ACL;
471 fprintf(stderr, "Failed to getxattr %s: %s\n", filename,
478 printf("# filename: %s\n", filename);
479 parse_sec_desc((struct cifs_ntsd *)attrval, attrlen, raw);
486 static int recursive(const char *filename, const struct stat *sb, int tflag, struct FTW *ftwbuf)
491 return getcifsacl(filename);
495 main(const int argc, char *const argv[])
498 execname = basename(argv[0]);
499 int do_recursive = 0;
503 fprintf(stderr, "%s: you must specify a filename.\n", execname);
504 printf("Try `getcifsacl -h' for more information.\n");
508 while ((c = getopt_long(argc, argv, "Rrhv", NULL, NULL)) != -1) {
511 printf("Version: %s\n", VERSION);
520 getcifsacl_usage(execname);
525 if (optind >= argc) {
526 printf("you must specify a filename after options.\n");
527 printf("Usage: getcifsacl [option] <file_name1> [<file_name2>,<file_name3>,...]\n");
531 if (!raw && !plugin_loaded) {
532 ret = init_plugin(&plugin_handle);
534 printf("WARNING: unable to initialize idmapping plugin: %s\n",
537 plugin_loaded = true;
541 for(; optind < argc; optind++) {
543 if (nftw(argv[optind], recursive, 20, 0) == -1)
544 fprintf(stderr, "Invalid filename %s: %s\n", argv[optind], strerror(errno));
546 tmp_rc = getcifsacl(argv[optind]);
554 exit_plugin(plugin_handle);