1 /* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
2
3 Copyright (C) 2002-2003, 2005-2018 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20 /* Without this pragma, gcc 4.7.0 20120126 may suggest that the
21 file_has_acl function might be candidate for attribute 'const' */
22 #if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
23 # pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
24 #endif
25
26 #include <config.h>
27
28 #include "acl.h"
29
30 #include "acl-internal.h"
31
32 #if GETXATTR_WITH_POSIX_ACLS
33 # include <sys/xattr.h>
34 # include <linux/xattr.h>
35 #endif
36
37 /* Return 1 if NAME has a nontrivial access control list,
38 0 if ACLs are not supported, or if NAME has no or only a base ACL,
39 and -1 (setting errno) on error. Note callers can determine
40 if ACLs are not supported as errno is set in that case also.
41 SB must be set to the stat buffer of NAME,
42 obtained through stat() or lstat(). */
43
44 int
file_has_acl(char const * name,struct stat const * sb)45 file_has_acl (char const *name, struct stat const *sb)
46 {
47 #if USE_ACL
48 if (! S_ISLNK (sb->st_mode))
49 {
50
51 # if GETXATTR_WITH_POSIX_ACLS
52
53 ssize_t ret;
54
55 ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0);
56 if (ret < 0 && errno == ENODATA)
57 ret = 0;
58 else if (ret > 0)
59 return 1;
60
61 if (ret == 0 && S_ISDIR (sb->st_mode))
62 {
63 ret = getxattr (name, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0);
64 if (ret < 0 && errno == ENODATA)
65 ret = 0;
66 else if (ret > 0)
67 return 1;
68 }
69
70 if (ret < 0)
71 return - acl_errno_valid (errno);
72 return ret;
73
74 # elif HAVE_ACL_GET_FILE
75
76 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
77 /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
78 int ret;
79
80 if (HAVE_ACL_EXTENDED_FILE) /* Linux */
81 {
82 /* On Linux, acl_extended_file is an optimized function: It only
83 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
84 ACL_TYPE_DEFAULT. */
85 ret = acl_extended_file (name);
86 }
87 else /* FreeBSD, Mac OS X, IRIX, Tru64 */
88 {
89 # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
90 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
91 and acl_get_file (name, ACL_TYPE_DEFAULT)
92 always return NULL / EINVAL. There is no point in making
93 these two useless calls. The real ACL is retrieved through
94 acl_get_file (name, ACL_TYPE_EXTENDED). */
95 acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
96 if (acl)
97 {
98 ret = acl_extended_nontrivial (acl);
99 acl_free (acl);
100 }
101 else
102 ret = -1;
103 # else /* FreeBSD, IRIX, Tru64 */
104 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
105 if (acl)
106 {
107 int saved_errno;
108
109 ret = acl_access_nontrivial (acl);
110 saved_errno = errno;
111 acl_free (acl);
112 errno = saved_errno;
113 # if HAVE_ACL_FREE_TEXT /* Tru64 */
114 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
115 returns NULL with errno not set. There is no point in
116 making this call. */
117 # else /* FreeBSD, IRIX */
118 /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
119 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
120 either both succeed or both fail; it depends on the
121 file system. Therefore there is no point in making the second
122 call if the first one already failed. */
123 if (ret == 0 && S_ISDIR (sb->st_mode))
124 {
125 acl = acl_get_file (name, ACL_TYPE_DEFAULT);
126 if (acl)
127 {
128 ret = (0 < acl_entries (acl));
129 acl_free (acl);
130 }
131 else
132 ret = -1;
133 }
134 # endif
135 }
136 else
137 ret = -1;
138 # endif
139 }
140 if (ret < 0)
141 return - acl_errno_valid (errno);
142 return ret;
143
144 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
145
146 # if defined ACL_NO_TRIVIAL
147
148 /* Solaris 10 (newer version), which has additional API declared in
149 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
150 acl_fromtext, ...). */
151 return acl_trivial (name);
152
153 # else /* Solaris, Cygwin, general case */
154
155 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
156 of Unixware. The acl() call returns the access and default ACL both
157 at once. */
158 {
159 /* Initially, try to read the entries into a stack-allocated buffer.
160 Use malloc if it does not fit. */
161 enum
162 {
163 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
164 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
165 };
166 aclent_t buf[alloc_init];
167 size_t alloc = alloc_init;
168 aclent_t *entries = buf;
169 aclent_t *malloced = NULL;
170 int count;
171
172 for (;;)
173 {
174 count = acl (name, GETACL, alloc, entries);
175 if (count < 0 && errno == ENOSPC)
176 {
177 /* Increase the size of the buffer. */
178 free (malloced);
179 if (alloc > alloc_max / 2)
180 {
181 errno = ENOMEM;
182 return -1;
183 }
184 alloc = 2 * alloc; /* <= alloc_max */
185 entries = malloced =
186 (aclent_t *) malloc (alloc * sizeof (aclent_t));
187 if (entries == NULL)
188 {
189 errno = ENOMEM;
190 return -1;
191 }
192 continue;
193 }
194 break;
195 }
196 if (count < 0)
197 {
198 if (errno == ENOSYS || errno == ENOTSUP)
199 ;
200 else
201 {
202 int saved_errno = errno;
203 free (malloced);
204 errno = saved_errno;
205 return -1;
206 }
207 }
208 else if (count == 0)
209 ;
210 else
211 {
212 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
213 returns only 3 entries for files with no ACL. But this is safe:
214 If there are more than 4 entries, there cannot be only the
215 "user::", "group::", "other:", and "mask:" entries. */
216 if (count > 4)
217 {
218 free (malloced);
219 return 1;
220 }
221
222 if (acl_nontrivial (count, entries))
223 {
224 free (malloced);
225 return 1;
226 }
227 }
228 free (malloced);
229 }
230
231 # ifdef ACE_GETACL
232 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
233 file systems (whereas the other ones are used in UFS file systems). */
234 {
235 /* Initially, try to read the entries into a stack-allocated buffer.
236 Use malloc if it does not fit. */
237 enum
238 {
239 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
240 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
241 };
242 ace_t buf[alloc_init];
243 size_t alloc = alloc_init;
244 ace_t *entries = buf;
245 ace_t *malloced = NULL;
246 int count;
247
248 for (;;)
249 {
250 count = acl (name, ACE_GETACL, alloc, entries);
251 if (count < 0 && errno == ENOSPC)
252 {
253 /* Increase the size of the buffer. */
254 free (malloced);
255 if (alloc > alloc_max / 2)
256 {
257 errno = ENOMEM;
258 return -1;
259 }
260 alloc = 2 * alloc; /* <= alloc_max */
261 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
262 if (entries == NULL)
263 {
264 errno = ENOMEM;
265 return -1;
266 }
267 continue;
268 }
269 break;
270 }
271 if (count < 0)
272 {
273 if (errno == ENOSYS || errno == EINVAL)
274 ;
275 else
276 {
277 int saved_errno = errno;
278 free (malloced);
279 errno = saved_errno;
280 return -1;
281 }
282 }
283 else if (count == 0)
284 ;
285 else
286 {
287 /* In the old (original Solaris 10) convention:
288 If there are more than 3 entries, there cannot be only the
289 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
290 In the newer Solaris 10 and Solaris 11 convention:
291 If there are more than 6 entries, there cannot be only the
292 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
293 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
294 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
295 if (count > 6)
296 {
297 free (malloced);
298 return 1;
299 }
300
301 if (acl_ace_nontrivial (count, entries))
302 {
303 free (malloced);
304 return 1;
305 }
306 }
307 free (malloced);
308 }
309 # endif
310
311 return 0;
312 # endif
313
314 # elif HAVE_GETACL /* HP-UX */
315
316 {
317 struct acl_entry entries[NACLENTRIES];
318 int count;
319
320 count = getacl (name, NACLENTRIES, entries);
321
322 if (count < 0)
323 {
324 /* ENOSYS is seen on newer HP-UX versions.
325 EOPNOTSUPP is typically seen on NFS mounts.
326 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
327 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
328 ;
329 else
330 return -1;
331 }
332 else if (count == 0)
333 return 0;
334 else /* count > 0 */
335 {
336 if (count > NACLENTRIES)
337 /* If NACLENTRIES cannot be trusted, use dynamic memory
338 allocation. */
339 abort ();
340
341 /* If there are more than 3 entries, there cannot be only the
342 (uid,%), (%,gid), (%,%) entries. */
343 if (count > 3)
344 return 1;
345
346 {
347 struct stat statbuf;
348
349 if (stat (name, &statbuf) < 0)
350 return -1;
351
352 return acl_nontrivial (count, entries);
353 }
354 }
355 }
356
357 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
358
359 {
360 struct acl entries[NACLVENTRIES];
361 int count;
362
363 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
364
365 if (count < 0)
366 {
367 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
368 EINVAL is seen on NFS in HP-UX 11.31. */
369 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
370 ;
371 else
372 return -1;
373 }
374 else if (count == 0)
375 return 0;
376 else /* count > 0 */
377 {
378 if (count > NACLVENTRIES)
379 /* If NACLVENTRIES cannot be trusted, use dynamic memory
380 allocation. */
381 abort ();
382
383 /* If there are more than 4 entries, there cannot be only the
384 four base ACL entries. */
385 if (count > 4)
386 return 1;
387
388 return aclv_nontrivial (count, entries);
389 }
390 }
391
392 # endif
393
394 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
395
396 acl_type_t type;
397 char aclbuf[1024];
398 void *acl = aclbuf;
399 size_t aclsize = sizeof (aclbuf);
400 mode_t mode;
401
402 for (;;)
403 {
404 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
405 is not true, in AIX 5.3. */
406 type.u64 = ACL_ANY;
407 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
408 break;
409 if (errno == ENOSYS)
410 return 0;
411 if (errno != ENOSPC)
412 {
413 if (acl != aclbuf)
414 {
415 int saved_errno = errno;
416 free (acl);
417 errno = saved_errno;
418 }
419 return -1;
420 }
421 aclsize = 2 * aclsize;
422 if (acl != aclbuf)
423 free (acl);
424 acl = malloc (aclsize);
425 if (acl == NULL)
426 {
427 errno = ENOMEM;
428 return -1;
429 }
430 }
431
432 if (type.u64 == ACL_AIXC)
433 {
434 int result = acl_nontrivial ((struct acl *) acl);
435 if (acl != aclbuf)
436 free (acl);
437 return result;
438 }
439 else if (type.u64 == ACL_NFS4)
440 {
441 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
442 if (acl != aclbuf)
443 free (acl);
444 return result;
445 }
446 else
447 {
448 /* A newer type of ACL has been introduced in the system.
449 We should better support it. */
450 if (acl != aclbuf)
451 free (acl);
452 errno = EINVAL;
453 return -1;
454 }
455
456 # elif HAVE_STATACL /* older AIX */
457
458 union { struct acl a; char room[4096]; } u;
459
460 if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
461 return -1;
462
463 return acl_nontrivial (&u.a);
464
465 # elif HAVE_ACLSORT /* NonStop Kernel */
466
467 {
468 struct acl entries[NACLENTRIES];
469 int count;
470
471 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
472
473 if (count < 0)
474 {
475 if (errno == ENOSYS || errno == ENOTSUP)
476 ;
477 else
478 return -1;
479 }
480 else if (count == 0)
481 return 0;
482 else /* count > 0 */
483 {
484 if (count > NACLENTRIES)
485 /* If NACLENTRIES cannot be trusted, use dynamic memory
486 allocation. */
487 abort ();
488
489 /* If there are more than 4 entries, there cannot be only the
490 four base ACL entries. */
491 if (count > 4)
492 return 1;
493
494 return acl_nontrivial (count, entries);
495 }
496 }
497
498 # endif
499 }
500 #endif
501
502 return 0;
503 }
504