source: trunk/src/sed/gnulib-tests/file-has-acl.c@ 3643

Last change on this file since 3643 was 3611, checked in by bird, 10 months ago

vendor/sed/current: GNU sed 4.9 (sed-4.9.tar.xz sha256:6e226b732e1cd739464ad6862bd1a1aba42d7982922da7a53519631d24975181)

File size: 14.8 KB
Line 
1/* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
2
3 Copyright (C) 2002-2003, 2005-2022 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
44int
45file_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 free (malloced);
210 return -1;
211 }
212 }
213 else if (count == 0)
214 ;
215 else
216 {
217 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
218 returns only 3 entries for files with no ACL. But this is safe:
219 If there are more than 4 entries, there cannot be only the
220 "user::", "group::", "other:", and "mask:" entries. */
221 if (count > 4)
222 {
223 free (malloced);
224 return 1;
225 }
226
227 if (acl_nontrivial (count, entries))
228 {
229 free (malloced);
230 return 1;
231 }
232 }
233 free (malloced);
234 }
235
236# ifdef ACE_GETACL
237 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
238 file systems (whereas the other ones are used in UFS file systems). */
239 {
240 /* Initially, try to read the entries into a stack-allocated buffer.
241 Use malloc if it does not fit. */
242 enum
243 {
244 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
245 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
246 };
247 ace_t buf[alloc_init];
248 size_t alloc = alloc_init;
249 ace_t *entries = buf;
250 ace_t *malloced = NULL;
251 int count;
252
253 for (;;)
254 {
255 count = acl (name, ACE_GETACL, alloc, entries);
256 if (count < 0 && errno == ENOSPC)
257 {
258 /* Increase the size of the buffer. */
259 free (malloced);
260 if (alloc > alloc_max / 2)
261 {
262 errno = ENOMEM;
263 return -1;
264 }
265 alloc = 2 * alloc; /* <= alloc_max */
266 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
267 if (entries == NULL)
268 {
269 errno = ENOMEM;
270 return -1;
271 }
272 continue;
273 }
274 break;
275 }
276 if (count < 0)
277 {
278 if (errno == ENOSYS || errno == EINVAL)
279 ;
280 else
281 {
282 free (malloced);
283 return -1;
284 }
285 }
286 else if (count == 0)
287 ;
288 else
289 {
290 /* In the old (original Solaris 10) convention:
291 If there are more than 3 entries, there cannot be only the
292 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
293 In the newer Solaris 10 and Solaris 11 convention:
294 If there are more than 6 entries, there cannot be only the
295 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
296 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
297 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
298 if (count > 6)
299 {
300 free (malloced);
301 return 1;
302 }
303
304 if (acl_ace_nontrivial (count, entries))
305 {
306 free (malloced);
307 return 1;
308 }
309 }
310 free (malloced);
311 }
312# endif
313
314 return 0;
315# endif
316
317# elif HAVE_GETACL /* HP-UX */
318
319 {
320 struct acl_entry entries[NACLENTRIES];
321 int count;
322
323 count = getacl (name, NACLENTRIES, entries);
324
325 if (count < 0)
326 {
327 /* ENOSYS is seen on newer HP-UX versions.
328 EOPNOTSUPP is typically seen on NFS mounts.
329 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
330 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
331 ;
332 else
333 return -1;
334 }
335 else if (count == 0)
336 return 0;
337 else /* count > 0 */
338 {
339 if (count > NACLENTRIES)
340 /* If NACLENTRIES cannot be trusted, use dynamic memory
341 allocation. */
342 abort ();
343
344 /* If there are more than 3 entries, there cannot be only the
345 (uid,%), (%,gid), (%,%) entries. */
346 if (count > 3)
347 return 1;
348
349 {
350 struct stat statbuf;
351
352 if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
353 return -1;
354
355 return acl_nontrivial (count, entries);
356 }
357 }
358 }
359
360# if HAVE_ACLV_H /* HP-UX >= 11.11 */
361
362 {
363 struct acl entries[NACLVENTRIES];
364 int count;
365
366 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
367
368 if (count < 0)
369 {
370 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
371 EINVAL is seen on NFS in HP-UX 11.31. */
372 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
373 ;
374 else
375 return -1;
376 }
377 else if (count == 0)
378 return 0;
379 else /* count > 0 */
380 {
381 if (count > NACLVENTRIES)
382 /* If NACLVENTRIES cannot be trusted, use dynamic memory
383 allocation. */
384 abort ();
385
386 /* If there are more than 4 entries, there cannot be only the
387 four base ACL entries. */
388 if (count > 4)
389 return 1;
390
391 return aclv_nontrivial (count, entries);
392 }
393 }
394
395# endif
396
397# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
398
399 acl_type_t type;
400 char aclbuf[1024];
401 void *acl = aclbuf;
402 size_t aclsize = sizeof (aclbuf);
403 mode_t mode;
404
405 for (;;)
406 {
407 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
408 is not true, in AIX 5.3. */
409 type.u64 = ACL_ANY;
410 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
411 break;
412 if (errno == ENOSYS)
413 return 0;
414 if (errno != ENOSPC)
415 {
416 if (acl != aclbuf)
417 free (acl);
418 return -1;
419 }
420 aclsize = 2 * aclsize;
421 if (acl != aclbuf)
422 free (acl);
423 acl = malloc (aclsize);
424 if (acl == NULL)
425 {
426 errno = ENOMEM;
427 return -1;
428 }
429 }
430
431 if (type.u64 == ACL_AIXC)
432 {
433 int result = acl_nontrivial ((struct acl *) acl);
434 if (acl != aclbuf)
435 free (acl);
436 return result;
437 }
438 else if (type.u64 == ACL_NFS4)
439 {
440 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
441 if (acl != aclbuf)
442 free (acl);
443 return result;
444 }
445 else
446 {
447 /* A newer type of ACL has been introduced in the system.
448 We should better support it. */
449 if (acl != aclbuf)
450 free (acl);
451 errno = EINVAL;
452 return -1;
453 }
454
455# elif HAVE_STATACL /* older AIX */
456
457 union { struct acl a; char room[4096]; } u;
458
459 if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
460 return -1;
461
462 return acl_nontrivial (&u.a);
463
464# elif HAVE_ACLSORT /* NonStop Kernel */
465
466 {
467 struct acl entries[NACLENTRIES];
468 int count;
469
470 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
471
472 if (count < 0)
473 {
474 if (errno == ENOSYS || errno == ENOTSUP)
475 ;
476 else
477 return -1;
478 }
479 else if (count == 0)
480 return 0;
481 else /* count > 0 */
482 {
483 if (count > NACLENTRIES)
484 /* If NACLENTRIES cannot be trusted, use dynamic memory
485 allocation. */
486 abort ();
487
488 /* If there are more than 4 entries, there cannot be only the
489 four base ACL entries. */
490 if (count > 4)
491 return 1;
492
493 return acl_nontrivial (count, entries);
494 }
495 }
496
497# endif
498 }
499#endif
500
501 return 0;
502}
Note: See TracBrowser for help on using the repository browser.