acl: Fix endless loop on Solaris with vxfs.
[gnulib.git] / lib / copy-acl.c
1 /* copy-acl.c - copy access control list from one file to another file
2
3    Copyright (C) 2002-2003, 2005-2012 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 <http://www.gnu.org/licenses/>.
17
18    Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
19
20 #include <config.h>
21
22 #include "acl.h"
23
24 #include "acl-internal.h"
25
26 #include "gettext.h"
27 #define _(msgid) gettext (msgid)
28
29
30 /* Copy access control lists from one file to another. If SOURCE_DESC is
31    a valid file descriptor, use file descriptor operations, else use
32    filename based operations on SRC_NAME. Likewise for DEST_DESC and
33    DST_NAME.
34    If access control lists are not available, fchmod the target file to
35    MODE.  Also sets the non-permission bits of the destination file
36    (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
37    Return 0 if successful.
38    Return -2 and set errno for an error relating to the source file.
39    Return -1 and set errno for an error relating to the destination file.  */
40
41 int
42 qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
43            int dest_desc, mode_t mode)
44 {
45 #if USE_ACL && HAVE_ACL_GET_FILE
46   /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
47   /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
48 # if !HAVE_ACL_TYPE_EXTENDED
49   /* Linux, FreeBSD, IRIX, Tru64 */
50
51   acl_t acl;
52   int ret;
53
54   if (HAVE_ACL_GET_FD && source_desc != -1)
55     acl = acl_get_fd (source_desc);
56   else
57     acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
58   if (acl == NULL)
59     {
60       if (ACL_NOT_WELL_SUPPORTED (errno))
61         return qset_acl (dst_name, dest_desc, mode);
62       else
63         return -2;
64     }
65
66   if (HAVE_ACL_SET_FD && dest_desc != -1)
67     ret = acl_set_fd (dest_desc, acl);
68   else
69     ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
70   if (ret != 0)
71     {
72       int saved_errno = errno;
73
74       if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl))
75         {
76           acl_free (acl);
77           return chmod_or_fchmod (dst_name, dest_desc, mode);
78         }
79       else
80         {
81           acl_free (acl);
82           chmod_or_fchmod (dst_name, dest_desc, mode);
83           errno = saved_errno;
84           return -1;
85         }
86     }
87   else
88     acl_free (acl);
89
90   if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
91     {
92       /* We did not call chmod so far, and either the mode and the ACL are
93          separate or special bits are to be set which don't fit into ACLs.  */
94
95       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
96         return -1;
97     }
98
99   if (S_ISDIR (mode))
100     {
101       acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
102       if (acl == NULL)
103         return -2;
104
105       if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
106         {
107           int saved_errno = errno;
108
109           acl_free (acl);
110           errno = saved_errno;
111           return -1;
112         }
113       else
114         acl_free (acl);
115     }
116   return 0;
117
118 # else /* HAVE_ACL_TYPE_EXTENDED */
119   /* MacOS X */
120
121   /* On MacOS X,  acl_get_file (name, ACL_TYPE_ACCESS)
122      and          acl_get_file (name, ACL_TYPE_DEFAULT)
123      always return NULL / EINVAL.  You have to use
124                   acl_get_file (name, ACL_TYPE_EXTENDED)
125      or           acl_get_fd (open (name, ...))
126      to retrieve an ACL.
127      On the other hand,
128                   acl_set_file (name, ACL_TYPE_ACCESS, acl)
129      and          acl_set_file (name, ACL_TYPE_DEFAULT, acl)
130      have the same effect as
131                   acl_set_file (name, ACL_TYPE_EXTENDED, acl):
132      Each of these calls sets the file's ACL.  */
133
134   acl_t acl;
135   int ret;
136
137   if (HAVE_ACL_GET_FD && source_desc != -1)
138     acl = acl_get_fd (source_desc);
139   else
140     acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
141   if (acl == NULL)
142     {
143       if (ACL_NOT_WELL_SUPPORTED (errno))
144         return qset_acl (dst_name, dest_desc, mode);
145       else
146         return -2;
147     }
148
149   if (HAVE_ACL_SET_FD && dest_desc != -1)
150     ret = acl_set_fd (dest_desc, acl);
151   else
152     ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
153   if (ret != 0)
154     {
155       int saved_errno = errno;
156
157       if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl))
158         {
159           acl_free (acl);
160           return chmod_or_fchmod (dst_name, dest_desc, mode);
161         }
162       else
163         {
164           acl_free (acl);
165           chmod_or_fchmod (dst_name, dest_desc, mode);
166           errno = saved_errno;
167           return -1;
168         }
169     }
170   else
171     acl_free (acl);
172
173   /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly.  */
174   return chmod_or_fchmod (dst_name, dest_desc, mode);
175
176 # endif
177
178 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
179
180   /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
181      of Unixware.  The acl() call returns the access and default ACL both
182      at once.  */
183 # ifdef ACE_GETACL
184   int ace_count;
185   ace_t *ace_entries;
186 # endif
187   int count;
188   aclent_t *entries;
189   int did_chmod;
190   int saved_errno;
191   int ret;
192
193 # ifdef ACE_GETACL
194   /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
195      file systems (whereas the other ones are used in UFS file systems).
196      There is an API
197        pathconf (name, _PC_ACL_ENABLED)
198        fpathconf (desc, _PC_ACL_ENABLED)
199      that allows to determine which of the two kinds of ACLs is supported
200      for the given file.  But some file systems may implement this call
201      incorrectly, so better not use it.
202      When fetching the source ACL, we simply fetch both ACL types.
203      When setting the destination ACL, we try either ACL types, assuming
204      that the kernel will translate the ACL from one form to the other.
205      (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
206      the description of ENOTSUP.)  */
207   for (;;)
208     {
209       ace_count = (source_desc != -1
210                    ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
211                    : acl (src_name, ACE_GETACLCNT, 0, NULL));
212
213       if (ace_count < 0)
214         {
215           if (errno == ENOSYS || errno == EINVAL)
216             {
217               ace_count = 0;
218               ace_entries = NULL;
219               break;
220             }
221           else
222             return -2;
223         }
224
225       if (ace_count == 0)
226         {
227           ace_entries = NULL;
228           break;
229         }
230
231       ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
232       if (ace_entries == NULL)
233         {
234           errno = ENOMEM;
235           return -2;
236         }
237
238       ret = (source_desc != -1
239              ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
240              : acl (src_name, ACE_GETACL, ace_count, ace_entries));
241       if (ret < 0)
242         {
243           free (ace_entries);
244           if (errno == ENOSYS || errno == EINVAL)
245             {
246               ace_count = 0;
247               ace_entries = NULL;
248               break;
249             }
250           else
251             return -2;
252         }
253       if (ret == ace_count)
254         break;
255       /* Huh? The number of ACL entries changed since the last call.
256          Repeat.  */
257     }
258 # endif
259
260   for (;;)
261     {
262       count = (source_desc != -1
263                ? facl (source_desc, GETACLCNT, 0, NULL)
264                : acl (src_name, GETACLCNT, 0, NULL));
265
266       if (count < 0)
267         {
268           if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
269             {
270               count = 0;
271               entries = NULL;
272               break;
273             }
274           else
275             return -2;
276         }
277
278       if (count == 0)
279         {
280           entries = NULL;
281           break;
282         }
283
284       entries = (aclent_t *) malloc (count * sizeof (aclent_t));
285       if (entries == NULL)
286         {
287           errno = ENOMEM;
288           return -2;
289         }
290
291       if ((source_desc != -1
292            ? facl (source_desc, GETACL, count, entries)
293            : acl (src_name, GETACL, count, entries))
294           == count)
295         break;
296       /* Huh? The number of ACL entries changed since the last call.
297          Repeat.  */
298     }
299
300   /* Is there an ACL of either kind?  */
301 # ifdef ACE_GETACL
302   if (ace_count == 0)
303 # endif
304     if (count == 0)
305       return qset_acl (dst_name, dest_desc, mode);
306
307   did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
308   saved_errno = 0; /* the first non-ignorable error code */
309
310   if (!MODE_INSIDE_ACL)
311     {
312       /* On Cygwin, it is necessary to call chmod before acl, because
313          chmod can change the contents of the ACL (in ways that don't
314          change the allowed accesses, but still visible).  */
315       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
316         saved_errno = errno;
317       did_chmod = 1;
318     }
319
320   /* If both ace_entries and entries are available, try SETACL before
321      ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
322      can.  */
323
324   if (count > 0)
325     {
326       ret = (dest_desc != -1
327              ? facl (dest_desc, SETACL, count, entries)
328              : acl (dst_name, SETACL, count, entries));
329       if (ret < 0 && saved_errno == 0)
330         {
331           saved_errno = errno;
332           if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
333               && !acl_nontrivial (count, entries))
334             saved_errno = 0;
335         }
336       else
337         did_chmod = 1;
338     }
339   free (entries);
340
341 # ifdef ACE_GETACL
342   if (ace_count > 0)
343     {
344       ret = (dest_desc != -1
345              ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
346              : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
347       if (ret < 0 && saved_errno == 0)
348         {
349           saved_errno = errno;
350           if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
351               && !acl_ace_nontrivial (ace_count, ace_entries))
352             saved_errno = 0;
353         }
354     }
355   free (ace_entries);
356 # endif
357
358   if (MODE_INSIDE_ACL
359       && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
360     {
361       /* We did not call chmod so far, and either the mode and the ACL are
362          separate or special bits are to be set which don't fit into ACLs.  */
363
364       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
365         {
366           if (saved_errno == 0)
367             saved_errno = errno;
368         }
369     }
370
371   if (saved_errno)
372     {
373       errno = saved_errno;
374       return -1;
375     }
376   return 0;
377
378 #elif USE_ACL && HAVE_GETACL /* HP-UX */
379
380   int count;
381   struct acl_entry entries[NACLENTRIES];
382 # if HAVE_ACLV_H
383   int aclv_count;
384   struct acl aclv_entries[NACLVENTRIES];
385 # endif
386   int did_chmod;
387   int saved_errno;
388   int ret;
389
390   for (;;)
391     {
392       count = (source_desc != -1
393                ? fgetacl (source_desc, 0, NULL)
394                : getacl (src_name, 0, NULL));
395
396       if (count < 0)
397         {
398           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
399             {
400               count = 0;
401               break;
402             }
403           else
404             return -2;
405         }
406
407       if (count == 0)
408         break;
409
410       if (count > NACLENTRIES)
411         /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
412         abort ();
413
414       if ((source_desc != -1
415            ? fgetacl (source_desc, count, entries)
416            : getacl (src_name, count, entries))
417           == count)
418         break;
419       /* Huh? The number of ACL entries changed since the last call.
420          Repeat.  */
421     }
422
423 # if HAVE_ACLV_H
424   for (;;)
425     {
426       aclv_count = acl ((char *) src_name, ACL_CNT, NACLVENTRIES, aclv_entries);
427
428       if (aclv_count < 0)
429         {
430           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
431             {
432               count = 0;
433               break;
434             }
435           else
436             return -2;
437         }
438
439       if (aclv_count == 0)
440         break;
441
442       if (aclv_count > NACLVENTRIES)
443         /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation.  */
444         abort ();
445
446       if (acl ((char *) src_name, ACL_GET, aclv_count, aclv_entries)
447           == aclv_count)
448         break;
449       /* Huh? The number of ACL entries changed since the last call.
450          Repeat.  */
451     }
452 # endif
453
454   if (count == 0)
455 # if HAVE_ACLV_H
456     if (aclv_count == 0)
457 # endif
458       return qset_acl (dst_name, dest_desc, mode);
459
460   did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
461   saved_errno = 0; /* the first non-ignorable error code */
462
463   if (count > 0)
464     {
465       ret = (dest_desc != -1
466              ? fsetacl (dest_desc, count, entries)
467              : setacl (dst_name, count, entries));
468       if (ret < 0 && saved_errno == 0)
469         {
470           saved_errno = errno;
471           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
472             {
473               struct stat source_statbuf;
474
475               if ((source_desc != -1
476                    ? fstat (source_desc, &source_statbuf)
477                    : stat (src_name, &source_statbuf)) == 0)
478                 {
479                   if (!acl_nontrivial (count, entries, &source_statbuf))
480                     saved_errno = 0;
481                 }
482               else
483                 saved_errno = errno;
484             }
485         }
486       else
487         did_chmod = 1;
488     }
489
490 # if HAVE_ACLV_H
491   if (aclv_count > 0)
492     {
493       ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
494       if (ret < 0 && saved_errno == 0)
495         {
496           saved_errno = errno;
497           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
498             {
499               if (!aclv_nontrivial (aclv_count, aclv_entries))
500                 saved_errno = 0;
501             }
502         }
503       else
504         did_chmod = 1;
505     }
506 # endif
507
508   if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
509     {
510       /* We did not call chmod so far, and special bits are to be set which
511          don't fit into ACLs.  */
512
513       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
514         {
515           if (saved_errno == 0)
516             saved_errno = errno;
517         }
518     }
519
520   if (saved_errno)
521     {
522       errno = saved_errno;
523       return -1;
524     }
525   return 0;
526
527 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
528
529   /* TODO */
530
531 #elif USE_ACL && HAVE_STATACL /* older AIX */
532
533   union { struct acl a; char room[4096]; } u;
534   int ret;
535
536   if ((source_desc != -1
537        ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
538        : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
539       < 0)
540     return -2;
541
542   ret = (dest_desc != -1
543          ? fchacl (dest_desc, &u.a, u.a.acl_len)
544          : chacl (dst_name, &u.a, u.a.acl_len));
545   if (ret < 0)
546     {
547       int saved_errno = errno;
548
549       chmod_or_fchmod (dst_name, dest_desc, mode);
550       errno = saved_errno;
551       return -1;
552     }
553
554   /* No need to call chmod_or_fchmod at this point, since the mode bits
555      S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL.  */
556
557   return 0;
558
559 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
560
561   int count;
562   struct acl entries[NACLENTRIES];
563   int ret;
564
565   for (;;)
566     {
567       count = acl ((char *) src_name, ACL_CNT, NACLENTRIES, NULL);
568
569       if (count < 0)
570         {
571           if (0)
572             {
573               count = 0;
574               break;
575             }
576           else
577             return -2;
578         }
579
580       if (count == 0)
581         break;
582
583       if (count > NACLENTRIES)
584         /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
585         abort ();
586
587       if (acl ((char *) src_name, ACL_GET, count, entries) == count)
588         break;
589       /* Huh? The number of ACL entries changed since the last call.
590          Repeat.  */
591     }
592
593   if (count == 0)
594     return qset_acl (dst_name, dest_desc, mode);
595
596   ret = acl ((char *) dst_name, ACL_SET, count, entries);
597   if (ret < 0)
598     {
599       int saved_errno = errno;
600
601       if (0)
602         {
603           if (!acl_nontrivial (count, entries))
604             return chmod_or_fchmod (dst_name, dest_desc, mode);
605         }
606
607       chmod_or_fchmod (dst_name, dest_desc, mode);
608       errno = saved_errno;
609       return -1;
610     }
611
612   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
613     {
614       /* We did not call chmod so far, and either the mode and the ACL are
615          separate or special bits are to be set which don't fit into ACLs.  */
616
617       return chmod_or_fchmod (dst_name, dest_desc, mode);
618     }
619   return 0;
620
621 #else
622
623   return qset_acl (dst_name, dest_desc, mode);
624
625 #endif
626 }
627
628
629 /* Copy access control lists from one file to another. If SOURCE_DESC is
630    a valid file descriptor, use file descriptor operations, else use
631    filename based operations on SRC_NAME. Likewise for DEST_DESC and
632    DST_NAME.
633    If access control lists are not available, fchmod the target file to
634    MODE.  Also sets the non-permission bits of the destination file
635    (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
636    Return 0 if successful, otherwise output a diagnostic and return a
637    negative error code.  */
638
639 int
640 copy_acl (const char *src_name, int source_desc, const char *dst_name,
641           int dest_desc, mode_t mode)
642 {
643   int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode);
644   switch (ret)
645     {
646     case -2:
647       error (0, errno, "%s", quote (src_name));
648       break;
649
650     case -1:
651       error (0, errno, _("preserving permissions for %s"), quote (dst_name));
652       break;
653
654     default:
655       break;
656     }
657   return ret;
658 }