58ff54aec7a79e5e6ae93dd73c2854c067ddd192
[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-2013 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, Mac OS 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   /* Mac OS X */
120
121   /* On Mac OS 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   struct acl_entry entries[NACLENTRIES];
381   int count;
382 # if HAVE_ACLV_H
383   struct acl aclv_entries[NACLVENTRIES];
384   int aclv_count;
385 # endif
386   int did_chmod;
387   int saved_errno;
388   int ret;
389
390   count = (source_desc != -1
391            ? fgetacl (source_desc, NACLENTRIES, entries)
392            : getacl (src_name, NACLENTRIES, entries));
393
394   if (count < 0)
395     {
396       if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
397         count = 0;
398       else
399         return -2;
400     }
401   else if (count > 0)
402     {
403       if (count > NACLENTRIES)
404         /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
405         abort ();
406     }
407
408 # if HAVE_ACLV_H
409   aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
410
411   if (aclv_count < 0)
412     {
413       if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
414         count = 0;
415       else
416         return -2;
417     }
418   else if (aclv_count > 0)
419     {
420       if (aclv_count > NACLVENTRIES)
421         /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation.  */
422         abort ();
423     }
424 # endif
425
426   if (count == 0)
427 # if HAVE_ACLV_H
428     if (aclv_count == 0)
429 # endif
430       return qset_acl (dst_name, dest_desc, mode);
431
432   did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
433   saved_errno = 0; /* the first non-ignorable error code */
434
435   if (count > 0)
436     {
437       ret = (dest_desc != -1
438              ? fsetacl (dest_desc, count, entries)
439              : setacl (dst_name, count, entries));
440       if (ret < 0 && saved_errno == 0)
441         {
442           saved_errno = errno;
443           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
444             {
445               struct stat source_statbuf;
446
447               if ((source_desc != -1
448                    ? fstat (source_desc, &source_statbuf)
449                    : stat (src_name, &source_statbuf)) == 0)
450                 {
451                   if (!acl_nontrivial (count, entries, &source_statbuf))
452                     saved_errno = 0;
453                 }
454               else
455                 saved_errno = errno;
456             }
457         }
458       else
459         did_chmod = 1;
460     }
461
462 # if HAVE_ACLV_H
463   if (aclv_count > 0)
464     {
465       ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
466       if (ret < 0 && saved_errno == 0)
467         {
468           saved_errno = errno;
469           if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
470             {
471               if (!aclv_nontrivial (aclv_count, aclv_entries))
472                 saved_errno = 0;
473             }
474         }
475       else
476         did_chmod = 1;
477     }
478 # endif
479
480   if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
481     {
482       /* We did not call chmod so far, and special bits are to be set which
483          don't fit into ACLs.  */
484
485       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
486         {
487           if (saved_errno == 0)
488             saved_errno = errno;
489         }
490     }
491
492   if (saved_errno)
493     {
494       errno = saved_errno;
495       return -1;
496     }
497   return 0;
498
499 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
500
501   /* TODO */
502
503 #elif USE_ACL && HAVE_STATACL /* older AIX */
504
505   union { struct acl a; char room[4096]; } u;
506   int ret;
507
508   if ((source_desc != -1
509        ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
510        : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
511       < 0)
512     return -2;
513
514   ret = (dest_desc != -1
515          ? fchacl (dest_desc, &u.a, u.a.acl_len)
516          : chacl (dst_name, &u.a, u.a.acl_len));
517   if (ret < 0)
518     {
519       int saved_errno = errno;
520
521       chmod_or_fchmod (dst_name, dest_desc, mode);
522       errno = saved_errno;
523       return -1;
524     }
525
526   /* No need to call chmod_or_fchmod at this point, since the mode bits
527      S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL.  */
528
529   return 0;
530
531 #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
532
533   struct acl entries[NACLENTRIES];
534   int count;
535   int ret;
536
537   count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
538
539   if (count < 0)
540     {
541       if (0)
542         count = 0;
543       else
544         return -2;
545     }
546   else if (count > 0)
547     {
548       if (count > NACLENTRIES)
549         /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
550         abort ();
551     }
552
553   if (count == 0)
554     return qset_acl (dst_name, dest_desc, mode);
555
556   ret = acl ((char *) dst_name, ACL_SET, count, entries);
557   if (ret < 0)
558     {
559       int saved_errno = errno;
560
561       if (0)
562         {
563           if (!acl_nontrivial (count, entries))
564             return chmod_or_fchmod (dst_name, dest_desc, mode);
565         }
566
567       chmod_or_fchmod (dst_name, dest_desc, mode);
568       errno = saved_errno;
569       return -1;
570     }
571
572   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
573     {
574       /* We did not call chmod so far, and either the mode and the ACL are
575          separate or special bits are to be set which don't fit into ACLs.  */
576
577       return chmod_or_fchmod (dst_name, dest_desc, mode);
578     }
579   return 0;
580
581 #else
582
583   return qset_acl (dst_name, dest_desc, mode);
584
585 #endif
586 }
587
588
589 /* Copy access control lists from one file to another. If SOURCE_DESC is
590    a valid file descriptor, use file descriptor operations, else use
591    filename based operations on SRC_NAME. Likewise for DEST_DESC and
592    DST_NAME.
593    If access control lists are not available, fchmod the target file to
594    MODE.  Also sets the non-permission bits of the destination file
595    (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
596    Return 0 if successful, otherwise output a diagnostic and return a
597    negative error code.  */
598
599 int
600 copy_acl (const char *src_name, int source_desc, const char *dst_name,
601           int dest_desc, mode_t mode)
602 {
603   int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode);
604   switch (ret)
605     {
606     case -2:
607       error (0, errno, "%s", quote (src_name));
608       break;
609
610     case -1:
611       error (0, errno, _("preserving permissions for %s"), quote (dst_name));
612       break;
613
614     default:
615       break;
616     }
617   return ret;
618 }