LCOV - code coverage report
Current view: top level - lib - acl.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 9 16 56.2 %
Date: 2018-01-30 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* acl.c - access control lists
       2             : 
       3             :    Copyright (C) 2002, 2003, 2005, 2006, 2007 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 and Andreas Gruenbacher.  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include "acl.h"
      23             : 
      24             : #include "acl-internal.h"
      25             : 
      26             : /* If DESC is a valid file descriptor use fchmod to change the
      27             :    file's mode to MODE on systems that have fchown. On systems
      28             :    that don't have fchown and if DESC is invalid, use chown on
      29             :    NAME instead.  */
      30             : 
      31             : int
      32          15 : chmod_or_fchmod (const char *name, int desc, mode_t mode)
      33             : {
      34          15 :   if (HAVE_FCHMOD && desc != -1)
      35          15 :     return fchmod (desc, mode);
      36             :   else
      37           0 :     return chmod (name, mode);
      38             : }
      39             : 
      40             : /* Copy access control lists from one file to another. If SOURCE_DESC is
      41             :    a valid file descriptor, use file descriptor operations, else use
      42             :    filename based operations on SRC_NAME. Likewise for DEST_DESC and
      43             :    DST_NAME.
      44             :    If access control lists are not available, fchmod the target file to
      45             :    MODE.  Also sets the non-permission bits of the destination file
      46             :    (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
      47             :    Return 0 if successful, otherwise output a diagnostic and return -1.  */
      48             : 
      49             : int
      50           0 : copy_acl (const char *src_name, int source_desc, const char *dst_name,
      51             :           int dest_desc, mode_t mode)
      52             : {
      53             :   int ret;
      54             : 
      55             : #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
      56             :   /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
      57             : 
      58             :   acl_t acl;
      59             :   if (HAVE_ACL_GET_FD && source_desc != -1)
      60             :     acl = acl_get_fd (source_desc);
      61             :   else
      62             :     acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
      63             :   if (acl == NULL)
      64             :     {
      65             :       if (ACL_NOT_WELL_SUPPORTED (errno))
      66             :         return set_acl (dst_name, dest_desc, mode);
      67             :       else
      68             :         {
      69             :           error (0, errno, "%s", quote (src_name));
      70             :           return -1;
      71             :         }
      72             :     }
      73             : 
      74             :   if (HAVE_ACL_SET_FD && dest_desc != -1)
      75             :     ret = acl_set_fd (dest_desc, acl);
      76             :   else
      77             :     ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
      78             :   if (ret != 0)
      79             :     {
      80             :       int saved_errno = errno;
      81             : 
      82             :       if (ACL_NOT_WELL_SUPPORTED (errno))
      83             :         {
      84             :           int n = acl_entries (acl);
      85             : 
      86             :           acl_free (acl);
      87             :           /* On most hosts an ACL is trivial if n == 3, and it cannot be
      88             :              less than 3.  On IRIX 6.5 it is also trivial if n == -1.
      89             :              For simplicity and safety, assume the ACL is trivial if n <= 3.
      90             :              Also see file-has-acl.c for some of the other possibilities;
      91             :              it's not clear whether that complexity is needed here.  */
      92             :           if (n <= 3)
      93             :             {
      94             :               if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
      95             :                 saved_errno = errno;
      96             :               else
      97             :                 return 0;
      98             :             }
      99             :           else
     100             :             chmod_or_fchmod (dst_name, dest_desc, mode);
     101             :         }
     102             :       else
     103             :         {
     104             :           acl_free (acl);
     105             :           chmod_or_fchmod (dst_name, dest_desc, mode);
     106             :         }
     107             :       error (0, saved_errno, _("preserving permissions for %s"),
     108             :              quote (dst_name));
     109             :       return -1;
     110             :     }
     111             :   else
     112             :     acl_free (acl);
     113             : 
     114             :   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
     115             :     {
     116             :       /* We did not call chmod so far, so the special bits have not yet
     117             :          been set.  */
     118             : 
     119             :       if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
     120             :         {
     121             :           error (0, errno, _("preserving permissions for %s"),
     122             :                  quote (dst_name));
     123             :           return -1;
     124             :         }
     125             :     }
     126             : 
     127             :   if (S_ISDIR (mode))
     128             :     {
     129             :       acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
     130             :       if (acl == NULL)
     131             :         {
     132             :           error (0, errno, "%s", quote (src_name));
     133             :           return -1;
     134             :         }
     135             : 
     136             :       if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
     137             :         {
     138             :           error (0, errno, _("preserving permissions for %s"),
     139             :                  quote (dst_name));
     140             :           acl_free (acl);
     141             :           return -1;
     142             :         }
     143             :       else
     144             :         acl_free (acl);
     145             :     }
     146             :   return 0;
     147             : 
     148             : #else
     149             : 
     150             : # if USE_ACL && defined ACL_NO_TRIVIAL
     151             :   /* Solaris 10 NFSv4 ACLs.  */
     152             :   acl_t *aclp = NULL;
     153             :   ret = (source_desc < 0
     154             :          ? acl_get (src_name, ACL_NO_TRIVIAL, &aclp)
     155             :          : facl_get (source_desc, ACL_NO_TRIVIAL, &aclp));
     156             :   if (ret != 0 && errno != ENOSYS)
     157             :     {
     158             :       error (0, errno, "%s", quote (src_name));
     159             :       return ret;
     160             :     }
     161             : # endif
     162             : 
     163           0 :   ret = qset_acl (dst_name, dest_desc, mode);
     164           0 :   if (ret != 0)
     165           0 :     error (0, errno, _("preserving permissions for %s"), quote (dst_name));
     166             : 
     167             : # if USE_ACL && defined ACL_NO_TRIVIAL
     168             :   if (ret == 0 && aclp)
     169             :     {
     170             :       ret = (dest_desc < 0
     171             :              ? acl_set (dst_name, aclp)
     172             :              : facl_set (dest_desc, aclp));
     173             :       if (ret != 0)
     174             :         error (0, errno, _("preserving permissions for %s"), quote (dst_name));
     175             :       acl_free (aclp);
     176             :     }
     177             : # endif
     178             : 
     179           0 :   return ret;
     180             : #endif
     181             : }
     182             : 
     183             : /* Set the access control lists of a file. If DESC is a valid file
     184             :    descriptor, use file descriptor operations where available, else use
     185             :    filename based operations on NAME.  If access control lists are not
     186             :    available, fchmod the target file to MODE.  Also sets the
     187             :    non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
     188             :    to those from MODE if any are set.  System call return value
     189             :    semantics.  */
     190             : 
     191             : int
     192          15 : qset_acl (char const *name, int desc, mode_t mode)
     193             : {
     194             : #if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
     195             :   /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
     196             : 
     197             :   /* We must also have have_acl_from_text and acl_delete_def_file.
     198             :      (acl_delete_def_file could be emulated with acl_init followed
     199             :       by acl_set_file, but acl_set_file with an empty acl is
     200             :       unspecified.)  */
     201             : 
     202             : # ifndef HAVE_ACL_FROM_TEXT
     203             : #  error Must have acl_from_text (see POSIX 1003.1e draft 17).
     204             : # endif
     205             : # ifndef HAVE_ACL_DELETE_DEF_FILE
     206             : #  error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
     207             : # endif
     208             : 
     209             :   acl_t acl;
     210             :   int ret;
     211             : 
     212             :   if (HAVE_ACL_FROM_MODE)
     213             :     {
     214             :       acl = acl_from_mode (mode);
     215             :       if (!acl)
     216             :         return -1;
     217             :     }
     218             :   else
     219             :     {
     220             :       char acl_text[] = "u::---,g::---,o::---";
     221             : 
     222             :       if (mode & S_IRUSR) acl_text[ 3] = 'r';
     223             :       if (mode & S_IWUSR) acl_text[ 4] = 'w';
     224             :       if (mode & S_IXUSR) acl_text[ 5] = 'x';
     225             :       if (mode & S_IRGRP) acl_text[10] = 'r';
     226             :       if (mode & S_IWGRP) acl_text[11] = 'w';
     227             :       if (mode & S_IXGRP) acl_text[12] = 'x';
     228             :       if (mode & S_IROTH) acl_text[17] = 'r';
     229             :       if (mode & S_IWOTH) acl_text[18] = 'w';
     230             :       if (mode & S_IXOTH) acl_text[19] = 'x';
     231             : 
     232             :       acl = acl_from_text (acl_text);
     233             :       if (!acl)
     234             :         return -1;
     235             :     }
     236             :   if (HAVE_ACL_SET_FD && desc != -1)
     237             :     ret = acl_set_fd (desc, acl);
     238             :   else
     239             :     ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
     240             :   if (ret != 0)
     241             :     {
     242             :       int saved_errno = errno;
     243             :       acl_free (acl);
     244             : 
     245             :       if (ACL_NOT_WELL_SUPPORTED (errno))
     246             :         {
     247             :           if (chmod_or_fchmod (name, desc, mode) != 0)
     248             :             saved_errno = errno;
     249             :           else
     250             :             return 0;
     251             :         }
     252             :       errno = saved_errno;
     253             :       return -1;
     254             :     }
     255             :   else
     256             :     acl_free (acl);
     257             : 
     258             :   if (S_ISDIR (mode) && acl_delete_def_file (name))
     259             :     return -1;
     260             : 
     261             :   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
     262             :     {
     263             :       /* We did not call chmod so far, so the special bits have not yet
     264             :          been set.  */
     265             : 
     266             :       if (chmod_or_fchmod (name, desc, mode))
     267             :         return -1;
     268             :     }
     269             :   return 0;
     270             : #else
     271             : 
     272             : # if USE_ACL && defined ACL_NO_TRIVIAL
     273             : 
     274             :   /* Solaris 10, with NFSv4 ACLs.  */
     275             :   acl_t *aclp;
     276             :   char acl_text[] = "user::---,group::---,mask:---,other:---";
     277             : 
     278             :   if (mode & S_IRUSR) acl_text[ 6] = 'r';
     279             :   if (mode & S_IWUSR) acl_text[ 7] = 'w';
     280             :   if (mode & S_IXUSR) acl_text[ 8] = 'x';
     281             :   if (mode & S_IRGRP) acl_text[17] = acl_text[26] = 'r';
     282             :   if (mode & S_IWGRP) acl_text[18] = acl_text[27] = 'w';
     283             :   if (mode & S_IXGRP) acl_text[19] = acl_text[28] = 'x';
     284             :   if (mode & S_IROTH) acl_text[36] = 'r';
     285             :   if (mode & S_IWOTH) acl_text[37] = 'w';
     286             :   if (mode & S_IXOTH) acl_text[38] = 'x';
     287             : 
     288             :   if (acl_fromtext (acl_text, &aclp) != 0)
     289             :     {
     290             :       errno = ENOMEM;
     291             :       return -1;
     292             :     }
     293             :   else
     294             :     {
     295             :       int acl_result = (desc < 0 ? acl_set (name, aclp) : facl_set (desc, aclp));
     296             :       int acl_errno = errno;
     297             :       acl_free (aclp);
     298             :       if (acl_result == 0 || acl_errno != ENOSYS)
     299             :         {
     300             :           errno = acl_errno;
     301             :           return acl_result;
     302             :         }
     303             :     }
     304             : # endif
     305             : 
     306          15 :   return chmod_or_fchmod (name, desc, mode);
     307             : 
     308             : #endif
     309             : }
     310             : 
     311             : /* As with qset_acl, but also output a diagnostic on failure.  */
     312             : 
     313             : int
     314          15 : set_acl (char const *name, int desc, mode_t mode)
     315             : {
     316          15 :   int r = qset_acl (name, desc, mode);
     317          15 :   if (r != 0)
     318           0 :     error (0, errno, _("setting permissions for %s"), quote (name));
     319          15 :   return r;
     320             : }

Generated by: LCOV version 1.10