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 */
39 #include <sys/xattr.h>
42 static const char *prog;
45 print_each_ace_mask(uint32_t mask)
47 if ((mask & ALL_READ_BITS) && ((mask & EREAD) != EREAD &&
48 (mask & OREAD) != OREAD && (mask & BREAD) != BREAD)) {
53 if ((mask & ALL_WRITE_BITS) && (mask & EWRITE) != EWRITE) {
58 if ((mask & EREAD) == EREAD || (mask & OREAD) == OREAD ||
59 (mask & BREAD) == BREAD)
61 if ((mask & EWRITE) == EWRITE)
63 if ((mask & EXEC) == EXEC)
65 if ((mask & DELETE) == DELETE)
67 if ((mask & WRITE_DAC) == WRITE_DAC)
69 if ((mask & WRITE_OWNER) == WRITE_OWNER)
74 print_ace_mask(uint32_t mask, int raw)
77 printf("0x%x\n", mask);
81 if (mask == FULL_CONTROL)
83 else if (mask == CHANGE)
85 else if (mask == DELETE)
87 else if (mask == EREAD)
89 else if (mask & DELDHLD)
92 print_each_ace_mask(mask);
99 print_ace_flags(uint8_t flags, int raw)
104 printf("0x%x", flags);
108 if (flags & OBJECT_INHERIT_FLAG) {
115 if (flags & CONTAINER_INHERIT_FLAG) {
122 if (flags & NO_PROPAGATE_INHERIT_FLAG) {
129 if (flags & INHERIT_ONLY_FLAG) {
136 if (flags & INHERITED_ACE_FLAG) {
149 print_ace_type(uint8_t acetype, int raw)
152 printf("0x%x", acetype);
163 case ACCESS_ALLOWED_OBJECT:
164 printf("OBJECT_ALLOWED");
166 case ACCESS_DENIED_OBJECT:
167 printf("OBJECT_DENIED");
176 * Winbind keeps wbcDomainSid fields in host-endian. Copy fields from the
177 * csid to the wsid, while converting the subauthority fields from LE.
180 csid_to_wsid(struct wbcDomainSid *wsid, const struct cifs_sid *csid)
184 wsid->sid_rev_num = csid->revision;
185 wsid->num_auths = csid->num_subauth;
186 for (i = 0; i < NUM_AUTHS; i++)
187 wsid->id_auth[i] = csid->authority[i];
188 for (i = 0; i < csid->num_subauth; i++)
189 wsid->sub_auths[i] = le32toh(csid->sub_auth[i]);
193 print_sid(struct cifs_sid *sidptr, int raw)
197 char *domain_name = NULL;
198 char *sidname = NULL;
199 enum wbcSidType sntype;
200 unsigned long long id_auth_val;
201 struct wbcDomainSid wsid;
203 csid_to_wsid(&wsid, sidptr);
208 rc = wbcLookupSid(&wsid, &domain_name, &sidname, &sntype);
209 if (WBC_ERROR_IS_OK(rc)) {
210 printf("%s", domain_name);
211 if (strlen(domain_name))
213 printf("%s", sidname);
218 printf("S-%hhu", wsid.sid_rev_num);
220 id_auth_val = (unsigned long long)wsid.id_auth[5];
221 id_auth_val += (unsigned long long)wsid.id_auth[4] << 8;
222 id_auth_val += (unsigned long long)wsid.id_auth[3] << 16;
223 id_auth_val += (unsigned long long)wsid.id_auth[2] << 24;
224 id_auth_val += (unsigned long long)wsid.id_auth[1] << 32;
225 id_auth_val += (unsigned long long)wsid.id_auth[0] << 48;
228 * MS-DTYP states that if the authority is >= 2^32, then it should be
229 * expressed as a hex value.
231 if (id_auth_val <= UINT_MAX)
232 printf("-%llu", id_auth_val);
234 printf("-0x%llx", id_auth_val);
236 for (i = 0; i < wsid.num_auths; i++)
237 printf("-%u", wsid.sub_auths[i]);
241 print_ace(struct cifs_ace *pace, char *end_of_acl, int raw)
245 /* make sure we can safely get to "size" */
246 if (end_of_acl < (char *)pace + offsetof(struct cifs_ace, size) + 1)
249 size = le16toh(pace->size);
251 /* 16 == size of cifs_ace when cifs_sid has no subauths */
255 /* validate that we do not go past end of acl */
256 if (end_of_acl < (char *)pace + size)
260 print_sid((struct cifs_sid *)&pace->sid, raw);
262 print_ace_type(pace->type, raw);
264 print_ace_flags(pace->flags, raw);
266 print_ace_mask(le32toh(pace->access_req), raw);
272 parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw)
278 struct cifs_ace *pace;
283 if (end_of_acl < (char *)pdacl + le16toh(pdacl->size))
286 acl_base = (char *)pdacl;
287 acl_size = sizeof(struct cifs_ctrl_acl);
289 num_aces = le32toh(pdacl->num_aces);
291 for (i = 0; i < num_aces; ++i) {
292 pace = (struct cifs_ace *) (acl_base + acl_size);
293 print_ace(pace, end_of_acl, raw);
294 acl_base = (char *)pace;
295 acl_size = le16toh(pace->size);
303 parse_sid(struct cifs_sid *psid, char *end_of_acl, char *title, int raw)
305 if (end_of_acl < (char *)psid + 8)
309 printf("%s:", title);
310 print_sid((struct cifs_sid *)psid, raw);
317 parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
321 char *end_of_acl = ((char *)pntsd) + acl_len;
322 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
323 struct cifs_ctrl_acl *dacl_ptr; /* no need for SACL ptr */
328 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
329 le32toh(pntsd->osidoffset));
330 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
331 le32toh(pntsd->gsidoffset));
332 dacloffset = le32toh(pntsd->dacloffset);
333 dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
334 printf("REVISION:0x%x\n", le16toh(pntsd->revision));
335 printf("CONTROL:0x%x\n", le16toh(pntsd->type));
337 rc = parse_sid(owner_sid_ptr, end_of_acl, "OWNER", raw);
341 rc = parse_sid(group_sid_ptr, end_of_acl, "GROUP", raw);
346 parse_dacl(dacl_ptr, end_of_acl, raw);
348 printf("No ACL\n"); /* BB grant all or default perms? */
354 getcifsacl_usage(void)
357 "%s: Display CIFS/NTFS ACL in a security descriptor of a file object\n",
359 fprintf(stderr, "Usage: %s [option] <file_name>\n", prog);
360 fprintf(stderr, "Valid options:\n");
361 fprintf(stderr, "\t-v Version of the program\n");
362 fprintf(stderr, "\n");
363 fprintf(stderr, "\t-r Display raw values of the ACE fields\n");
364 fprintf(stderr, "\nRefer to getcifsacl(1) manpage for details\n");
368 main(const int argc, char *const argv[])
372 size_t bufsize = BUFSIZE;
373 char *filename, *attrval;
375 prog = basename(argv[0]);
376 openlog(prog, 0, LOG_DAEMON);
378 while ((c = getopt_long(argc, argv, "r:v", NULL, NULL)) != -1) {
381 printf("Version: %s\n", VERSION);
391 if (raw && argc == 3)
401 if (bufsize >= XATTR_SIZE_MAX) {
402 printf("buffer to allocate exceeds max size of %d\n",
407 attrval = malloc(bufsize * sizeof(char));
409 printf("error allocating memory for attribute value buffer\n");
413 attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
415 if (errno == ERANGE) {
420 printf("getxattr error: %d\n", errno);
423 parse_sec_desc((struct cifs_ntsd *)attrval, attrlen, raw);