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