1 /* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
2
3 Copyright (C) 2002-2003, 2005-2021 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, Cygwin >= 2.5 */
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, Cygwin >= 2.5 */
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, Cygwin >= 2.5 */
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, Cygwin >= 2.5 */
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 # ifdef __CYGWIN__ /* Cygwin >= 2.5 */
129 ret = acl_access_nontrivial (acl);
130 saved_errno = errno;
131 acl_free (acl);
132 errno = saved_errno;
133 # else
134 ret = (0 < acl_entries (acl));
135 acl_free (acl);
136 # endif
137 }
138 else
139 ret = -1;
140 }
141 # endif
142 }
143 else
144 ret = -1;
145 # endif
146 }
147 if (ret < 0)
148 return - acl_errno_valid (errno);
149 return ret;
150
151 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
152
153 # if defined ACL_NO_TRIVIAL
154
155 /* Solaris 10 (newer version), which has additional API declared in
156 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
157 acl_fromtext, ...). */
158 return acl_trivial (name);
159
160 # else /* Solaris, Cygwin, general case */
161
162 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
163 of Unixware. The acl() call returns the access and default ACL both
164 at once. */
165 {
166 /* Initially, try to read the entries into a stack-allocated buffer.
167 Use malloc if it does not fit. */
168 enum
169 {
170 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
171 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
172 };
173 aclent_t buf[alloc_init];
174 size_t alloc = alloc_init;
175 aclent_t *entries = buf;
176 aclent_t *malloced = NULL;
177 int count;
178
179 for (;;)
180 {
181 count = acl (name, GETACL, alloc, entries);
182 if (count < 0 && errno == ENOSPC)
183 {
184 /* Increase the size of the buffer. */
185 free (malloced);
186 if (alloc > alloc_max / 2)
187 {
188 errno = ENOMEM;
189 return -1;
190 }
191 alloc = 2 * alloc; /* <= alloc_max */
192 entries = malloced =
193 (aclent_t *) malloc (alloc * sizeof (aclent_t));
194 if (entries == NULL)
195 {
196 errno = ENOMEM;
197 return -1;
198 }
199 continue;
200 }
201 break;
202 }
203 if (count < 0)
204 {
205 if (errno == ENOSYS || errno == ENOTSUP)
206 ;
207 else
208 {
209 int saved_errno = errno;
210 free (malloced);
211 errno = saved_errno;
212 return -1;
213 }
214 }
215 else if (count == 0)
216 ;
217 else
218 {
219 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
220 returns only 3 entries for files with no ACL. But this is safe:
221 If there are more than 4 entries, there cannot be only the
222 "user::", "group::", "other:", and "mask:" entries. */
223 if (count > 4)
224 {
225 free (malloced);
226 return 1;
227 }
228
229 if (acl_nontrivial (count, entries))
230 {
231 free (malloced);
232 return 1;
233 }
234 }
235 free (malloced);
236 }
237
238 # ifdef ACE_GETACL
239 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
240 file systems (whereas the other ones are used in UFS file systems). */
241 {
242 /* Initially, try to read the entries into a stack-allocated buffer.
243 Use malloc if it does not fit. */
244 enum
245 {
246 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
247 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
248 };
249 ace_t buf[alloc_init];
250 size_t alloc = alloc_init;
251 ace_t *entries = buf;
252 ace_t *malloced = NULL;
253 int count;
254
255 for (;;)
256 {
257 count = acl (name, ACE_GETACL, alloc, entries);
258 if (count < 0 && errno == ENOSPC)
259 {
260 /* Increase the size of the buffer. */
261 free (malloced);
262 if (alloc > alloc_max / 2)
263 {
264 errno = ENOMEM;
265 return -1;
266 }
267 alloc = 2 * alloc; /* <= alloc_max */
268 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
269 if (entries == NULL)
270 {
271 errno = ENOMEM;
272 return -1;
273 }
274 continue;
275 }
276 break;
277 }
278 if (count < 0)
279 {
280 if (errno == ENOSYS || errno == EINVAL)
281 ;
282 else
283 {
284 int saved_errno = errno;
285 free (malloced);
286 errno = saved_errno;
287 return -1;
288 }
289 }
290 else if (count == 0)
291 ;
292 else
293 {
294 /* In the old (original Solaris 10) convention:
295 If there are more than 3 entries, there cannot be only the
296 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
297 In the newer Solaris 10 and Solaris 11 convention:
298 If there are more than 6 entries, there cannot be only the
299 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
300 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
301 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
302 if (count > 6)
303 {
304 free (malloced);
305 return 1;
306 }
307
308 if (acl_ace_nontrivial (count, entries))
309 {
310 free (malloced);
311 return 1;
312 }
313 }
314 free (malloced);
315 }
316 # endif
317
318 return 0;
319 # endif
320
321 # elif HAVE_GETACL /* HP-UX */
322
323 {
324 struct acl_entry entries[NACLENTRIES];
325 int count;
326
327 count = getacl (name, NACLENTRIES, entries);
328
329 if (count < 0)
330 {
331 /* ENOSYS is seen on newer HP-UX versions.
332 EOPNOTSUPP is typically seen on NFS mounts.
333 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
334 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
335 ;
336 else
337 return -1;
338 }
339 else if (count == 0)
340 return 0;
341 else /* count > 0 */
342 {
343 if (count > NACLENTRIES)
344 /* If NACLENTRIES cannot be trusted, use dynamic memory
345 allocation. */
346 abort ();
347
348 /* If there are more than 3 entries, there cannot be only the
349 (uid,%), (%,gid), (%,%) entries. */
350 if (count > 3)
351 return 1;
352
353 {
354 struct stat statbuf;
355
356 if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
357 return -1;
358
359 return acl_nontrivial (count, entries);
360 }
361 }
362 }
363
364 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
365
366 {
367 struct acl entries[NACLVENTRIES];
368 int count;
369
370 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
371
372 if (count < 0)
373 {
374 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
375 EINVAL is seen on NFS in HP-UX 11.31. */
376 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
377 ;
378 else
379 return -1;
380 }
381 else if (count == 0)
382 return 0;
383 else /* count > 0 */
384 {
385 if (count > NACLVENTRIES)
386 /* If NACLVENTRIES cannot be trusted, use dynamic memory
387 allocation. */
388 abort ();
389
390 /* If there are more than 4 entries, there cannot be only the
391 four base ACL entries. */
392 if (count > 4)
393 return 1;
394
395 return aclv_nontrivial (count, entries);
396 }
397 }
398
399 # endif
400
401 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
402
403 acl_type_t type;
404 char aclbuf[1024];
405 void *acl = aclbuf;
406 size_t aclsize = sizeof (aclbuf);
407 mode_t mode;
408
409 for (;;)
410 {
411 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
412 is not true, in AIX 5.3. */
413 type.u64 = ACL_ANY;
414 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
415 break;
416 if (errno == ENOSYS)
417 return 0;
418 if (errno != ENOSPC)
419 {
420 if (acl != aclbuf)
421 {
422 int saved_errno = errno;
423 free (acl);
424 errno = saved_errno;
425 }
426 return -1;
427 }
428 aclsize = 2 * aclsize;
429 if (acl != aclbuf)
430 free (acl);
431 acl = malloc (aclsize);
432 if (acl == NULL)
433 {
434 errno = ENOMEM;
435 return -1;
436 }
437 }
438
439 if (type.u64 == ACL_AIXC)
440 {
441 int result = acl_nontrivial ((struct acl *) acl);
442 if (acl != aclbuf)
443 free (acl);
444 return result;
445 }
446 else if (type.u64 == ACL_NFS4)
447 {
448 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
449 if (acl != aclbuf)
450 free (acl);
451 return result;
452 }
453 else
454 {
455 /* A newer type of ACL has been introduced in the system.
456 We should better support it. */
457 if (acl != aclbuf)
458 free (acl);
459 errno = EINVAL;
460 return -1;
461 }
462
463 # elif HAVE_STATACL /* older AIX */
464
465 union { struct acl a; char room[4096]; } u;
466
467 if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
468 return -1;
469
470 return acl_nontrivial (&u.a);
471
472 # elif HAVE_ACLSORT /* NonStop Kernel */
473
474 {
475 struct acl entries[NACLENTRIES];
476 int count;
477
478 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
479
480 if (count < 0)
481 {
482 if (errno == ENOSYS || errno == ENOTSUP)
483 ;
484 else
485 return -1;
486 }
487 else if (count == 0)
488 return 0;
489 else /* count > 0 */
490 {
491 if (count > NACLENTRIES)
492 /* If NACLENTRIES cannot be trusted, use dynamic memory
493 allocation. */
494 abort ();
495
496 /* If there are more than 4 entries, there cannot be only the
497 four base ACL entries. */
498 if (count > 4)
499 return 1;
500
501 return acl_nontrivial (count, entries);
502 }
503 }
504
505 # endif
506 }
507 #endif
508
509 return 0;
510 }
511