cifscreds: fix up some whitespace, typos and build warnings in pam_cifscreds.c
[jlayton/cifs-utils.git] / getcifsacl.c
1 /*
2 * getcifsacl utility
3 *
4 * Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
5 *
6 * Used to display a security descriptor including ACL of a file object
7 * that belongs to a share mounted using option cifsacl.
8 *
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
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif /* HAVE_CONFIG_H */
25
26 #include <string.h>
27 #include <getopt.h>
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <ctype.h>
37 #include <sys/xattr.h>
38 #include "cifsacl.h"
39 #include "idmap_plugin.h"
40
41 static void *plugin_handle;
42 static bool plugin_loaded;
43
44 static void
45 print_each_ace_mask(uint32_t mask)
46 {
47         if ((mask & ALL_READ_BITS) && ((mask & EREAD) != EREAD &&
48                         (mask & OREAD) != OREAD && (mask & BREAD) != BREAD)) {
49                 printf("0x%x", mask);
50                 return;
51         }
52
53         if ((mask & ALL_WRITE_BITS) && (mask & EWRITE) != EWRITE) {
54                 printf("0x%x", mask);
55                 return;
56         }
57
58         if ((mask & EREAD) == EREAD || (mask & OREAD) == OREAD ||
59                         (mask & BREAD) == BREAD)
60                 printf("R");
61         if ((mask & EWRITE) == EWRITE)
62                 printf("W");
63         if ((mask & EXEC) == EXEC)
64                 printf("X");
65         if ((mask & DELETE) == DELETE)
66                 printf("D");
67         if ((mask & WRITE_DAC) == WRITE_DAC)
68                 printf("P");
69         if ((mask & WRITE_OWNER) == WRITE_OWNER)
70                 printf("O");
71 }
72
73 static void
74 print_ace_mask(uint32_t mask, int raw)
75 {
76         if (raw) {
77                 printf("0x%x\n", mask);
78                 return;
79         }
80
81         if (mask == FULL_CONTROL)
82                 printf("FULL");
83         else if (mask == CHANGE)
84                 printf("CHANGE");
85         else if (mask == DELETE)
86                 printf("D");
87         else if (mask == EREAD)
88                 printf("READ");
89         else if (mask & DELDHLD)
90                 printf("0x%x", mask);
91         else
92                 print_each_ace_mask(mask);
93
94         printf("\n");
95         return;
96 }
97
98 static void
99 print_ace_flags(uint8_t flags, int raw)
100 {
101         bool mflags = false;
102
103         if (raw) {
104                 printf("0x%x", flags);
105                 return;
106         }
107
108         if (flags & OBJECT_INHERIT_FLAG) {
109                 mflags = true;
110                 printf("OI");
111         }
112         if (flags & CONTAINER_INHERIT_FLAG) {
113                 if (mflags)
114                         printf("|");
115                 else
116                         mflags = true;
117                 printf("CI");
118         }
119         if (flags & NO_PROPAGATE_INHERIT_FLAG) {
120                 if (mflags)
121                         printf("|");
122                 else
123                         mflags = true;
124                 printf("NP");
125         }
126         if (flags & INHERIT_ONLY_FLAG) {
127                 if (mflags)
128                         printf("|");
129                 else
130                         mflags = true;
131                 printf("IO");
132         }
133         if (flags & INHERITED_ACE_FLAG) {
134                 if (mflags)
135                         printf("|");
136                 else
137                         mflags = true;
138                 printf("I");
139         }
140
141         if (!mflags)
142                 printf("0x0");
143 }
144
145 static void
146 print_ace_type(uint8_t acetype, int raw)
147 {
148         if (raw) {
149                 printf("0x%x", acetype);
150                 return;
151         }
152
153         switch (acetype) {
154         case ACCESS_ALLOWED:
155                 printf("ALLOWED");
156                 break;
157         case ACCESS_DENIED:
158                 printf("DENIED");
159                 break;
160         case ACCESS_ALLOWED_OBJECT:
161                 printf("OBJECT_ALLOWED");
162                 break;
163         case ACCESS_DENIED_OBJECT:
164                 printf("OBJECT_DENIED");
165                 break;
166         default:
167                 printf("UNKNOWN");
168                 break;
169         }
170 }
171
172 static void
173 print_sid(struct cifs_sid *csid, int raw)
174 {
175         int i, rc;
176         char *name;
177         unsigned long long id_auth_val;
178
179         if (raw || !plugin_loaded)
180                 goto print_sid_raw;
181
182         rc = sid_to_str(plugin_handle, csid, &name);
183         if (rc)
184                 goto print_sid_raw;
185
186         printf("%s", name);
187         free(name);
188         return;
189
190 print_sid_raw:
191         printf("S-%hhu", csid->revision);
192
193         id_auth_val = (unsigned long long)csid->authority[5];
194         id_auth_val += (unsigned long long)csid->authority[4] << 8;
195         id_auth_val += (unsigned long long)csid->authority[3] << 16;
196         id_auth_val += (unsigned long long)csid->authority[2] << 24;
197         id_auth_val += (unsigned long long)csid->authority[1] << 32;
198         id_auth_val += (unsigned long long)csid->authority[0] << 40;
199
200         /*
201          * MS-DTYP states that if the authority is >= 2^32, then it should be
202          * expressed as a hex value.
203          */
204         if (id_auth_val <= UINT_MAX)
205                 printf("-%llu", id_auth_val);
206         else
207                 printf("-0x%llx", id_auth_val);
208
209         for (i = 0; i < csid->num_subauth; i++)
210                 printf("-%u", le32toh(csid->sub_auth[i]));
211 }
212
213 static void
214 print_ace(struct cifs_ace *pace, char *end_of_acl, int raw)
215 {
216         uint16_t size;
217
218         /* make sure we can safely get to "size" */
219         if (end_of_acl < (char *)pace + offsetof(struct cifs_ace, size) + 1)
220                 return;
221
222         size = le16toh(pace->size);
223
224         /* 16 == size of cifs_ace when cifs_sid has no subauths */
225         if (size < 16)
226                 return;
227
228         /* validate that we do not go past end of acl */
229         if (end_of_acl < (char *)pace + size)
230                 return;
231
232         printf("ACL:");
233         print_sid((struct cifs_sid *)&pace->sid, raw);
234         printf(":");
235         print_ace_type(pace->type, raw);
236         printf("/");
237         print_ace_flags(pace->flags, raw);
238         printf("/");
239         print_ace_mask(le32toh(pace->access_req), raw);
240
241         return;
242 }
243
244 static void
245 parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw)
246 {
247         int i;
248         int num_aces = 0;
249         int acl_size;
250         char *acl_base;
251         struct cifs_ace *pace;
252
253         if (!pdacl)
254                 return;
255
256         if (end_of_acl < (char *)pdacl + le16toh(pdacl->size))
257                 return;
258
259         acl_base = (char *)pdacl;
260         acl_size = sizeof(struct cifs_ctrl_acl);
261
262         num_aces = le32toh(pdacl->num_aces);
263         if (num_aces  > 0) {
264                 for (i = 0; i < num_aces; ++i) {
265                         pace = (struct cifs_ace *) (acl_base + acl_size);
266                         print_ace(pace, end_of_acl, raw);
267                         acl_base = (char *)pace;
268                         acl_size = le16toh(pace->size);
269                 }
270         }
271
272         return;
273 }
274
275 static int
276 parse_sid(struct cifs_sid *psid, char *end_of_acl, char *title, int raw)
277 {
278         if (end_of_acl < (char *)psid + 8)
279                 return -EINVAL;
280
281         if (title)
282                 printf("%s:", title);
283         print_sid((struct cifs_sid *)psid, raw);
284         printf("\n");
285
286         return 0;
287 }
288
289 static int
290 parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
291 {
292         int rc;
293         uint32_t dacloffset;
294         char *end_of_acl = ((char *)pntsd) + acl_len;
295         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
296         struct cifs_ctrl_acl *dacl_ptr; /* no need for SACL ptr */
297
298         if (pntsd == NULL)
299                 return -EIO;
300
301         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
302                                 le32toh(pntsd->osidoffset));
303         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
304                                 le32toh(pntsd->gsidoffset));
305         dacloffset = le32toh(pntsd->dacloffset);
306         dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
307         printf("REVISION:0x%x\n", le16toh(pntsd->revision));
308         printf("CONTROL:0x%x\n", le16toh(pntsd->type));
309
310         rc = parse_sid(owner_sid_ptr, end_of_acl, "OWNER", raw);
311         if (rc)
312                 return rc;
313
314         rc = parse_sid(group_sid_ptr, end_of_acl, "GROUP", raw);
315         if (rc)
316                 return rc;
317
318         if (dacloffset)
319                 parse_dacl(dacl_ptr, end_of_acl, raw);
320         else
321                 printf("No ACL\n"); /* BB grant all or default perms? */
322
323         return 0;
324 }
325
326 static void
327 getcifsacl_usage(const char *prog)
328 {
329         fprintf(stderr,
330         "%s: Display CIFS/NTFS ACL in a security descriptor of a file object\n",
331                 prog);
332         fprintf(stderr, "Usage: %s [option] <file_name>\n", prog);
333         fprintf(stderr, "Valid options:\n");
334         fprintf(stderr, "\t-v   Version of the program\n");
335         fprintf(stderr, "\n");
336         fprintf(stderr, "\t-r   Display raw values of the ACE fields\n");
337         fprintf(stderr, "\nRefer to getcifsacl(1) manpage for details\n");
338 }
339
340 int
341 main(const int argc, char *const argv[])
342 {
343         int c, ret = 0;
344         bool raw = false;
345         ssize_t attrlen;
346         size_t bufsize = BUFSIZE;
347         char *filename, *attrval;
348
349         while ((c = getopt_long(argc, argv, "r:v", NULL, NULL)) != -1) {
350                 switch (c) {
351                 case 'v':
352                         printf("Version: %s\n", VERSION);
353                         goto out;
354                 case 'r':
355                         raw = true;
356                         break;
357                 default:
358                         break;
359                 }
360         }
361
362         if (raw && argc == 3)
363                 filename = argv[2];
364         else if (argc == 2)
365                 filename = argv[1];
366         else {
367                 getcifsacl_usage(basename(argv[0]));
368                 goto out;
369         }
370
371         if (!raw && !plugin_loaded) {
372                 ret = init_plugin(&plugin_handle);
373                 if (ret)
374                         printf("WARNING: unable to initialize idmapping plugin: %s\n",
375                                 plugin_errmsg);
376                 else
377                         plugin_loaded = true;
378         }
379
380 cifsacl:
381         if (bufsize >= XATTR_SIZE_MAX) {
382                 printf("buffer to allocate exceeds max size of %d\n",
383                                 XATTR_SIZE_MAX);
384                 ret = -1;
385                 goto out;
386         }
387
388         attrval = malloc(bufsize * sizeof(char));
389         if (!attrval) {
390                 printf("error allocating memory for attribute value buffer\n");
391                 ret = -1;
392                 goto out;
393         }
394
395         attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
396         if (attrlen == -1) {
397                 if (errno == ERANGE) {
398                         free(attrval);
399                         bufsize += BUFSIZE;
400                         goto cifsacl;
401                 } else
402                         printf("getxattr error: %d\n", errno);
403         }
404
405         parse_sec_desc((struct cifs_ntsd *)attrval, attrlen, raw);
406
407         free(attrval);
408 out:
409         if (plugin_loaded)
410                 exit_plugin(plugin_handle);
411         return ret;
412 }