acl-internal.h 8.88 KB
Newer Older
Paul Eggert's avatar
Paul Eggert committed
1
/* Internal implementation of access control lists.  -*- coding: utf-8 -*-
2

Paul Eggert's avatar
Paul Eggert committed
3
   Copyright (C) 2002-2003, 2005-2019 Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
Paul Eggert's avatar
Paul Eggert committed
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

   Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */

#include "acl.h"

#include <stdbool.h>
#include <stdlib.h>

/* All systems define the ACL related API in <sys/acl.h>.  */
#if HAVE_SYS_ACL_H
# include <sys/acl.h>
#endif
#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT
# define GETACLCNT ACL_CNT
#endif

Paul Eggert's avatar
Paul Eggert committed
33 34
/* On Linux and Cygwin >= 2.5, additional ACL related API is available in
   <acl/libacl.h>.  */
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#ifdef HAVE_ACL_LIBACL_H
# include <acl/libacl.h>
#endif

/* On HP-UX >= 11.11, additional ACL API is available in <aclv.h>.  */
#if HAVE_ACLV_H
# include <sys/types.h>
# include <aclv.h>
/* HP-UX 11.11 lacks these declarations.  */
extern int acl (char *, int, int, struct acl *);
extern int aclsort (int, int, struct acl *);
#endif

#include <errno.h>

#include <limits.h>
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif

#ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
#endif

#ifndef HAVE_FCHMOD
# define HAVE_FCHMOD false
# define fchmod(fd, mode) (-1)
#endif

Paul Eggert's avatar
Paul Eggert committed
64 65 66
#ifndef _GL_INLINE_HEADER_BEGIN
 #error "Please include config.h first."
#endif
67 68 69 70 71 72 73 74 75
_GL_INLINE_HEADER_BEGIN
#ifndef ACL_INTERNAL_INLINE
# define ACL_INTERNAL_INLINE _GL_INLINE
#endif

#if USE_ACL

# if HAVE_ACL_GET_FILE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
Paul Eggert's avatar
Paul Eggert committed
76
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

#  ifndef MIN_ACL_ENTRIES
#   define MIN_ACL_ENTRIES 4
#  endif

/* POSIX 1003.1e (draft 17) */
#  ifdef HAVE_ACL_GET_FD
/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument
   macro(!).  */
#   if HAVE_ACL_FREE_TEXT /* OSF/1 */
ACL_INTERNAL_INLINE acl_t
rpl_acl_get_fd (int fd)
{
  return acl_get_fd (fd, ACL_TYPE_ACCESS);
}
#    undef acl_get_fd
#    define acl_get_fd rpl_acl_get_fd
#   endif
#  else
#   define HAVE_ACL_GET_FD false
#   undef acl_get_fd
#   define acl_get_fd(fd) (NULL)
#  endif

/* POSIX 1003.1e (draft 17) */
#  ifdef HAVE_ACL_SET_FD
/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument
   macro(!).  */
#   if HAVE_ACL_FREE_TEXT /* OSF/1 */
ACL_INTERNAL_INLINE int
rpl_acl_set_fd (int fd, acl_t acl)
{
  return acl_set_fd (fd, ACL_TYPE_ACCESS, acl);
}
#    undef acl_set_fd
#    define acl_set_fd rpl_acl_set_fd
#   endif
#  else
#   define HAVE_ACL_SET_FD false
#   undef acl_set_fd
#   define acl_set_fd(fd, acl) (-1)
#  endif

/* POSIX 1003.1e (draft 13) */
#  if ! HAVE_ACL_FREE_TEXT
#   define acl_free_text(buf) acl_free (buf)
#  endif

/* Linux-specific */
Paul Eggert's avatar
Paul Eggert committed
126 127 128 129
/* Cygwin >= 2.5 implements this function, but it returns 1 for all
   directories, thus is unusable.  */
#  if !defined HAVE_ACL_EXTENDED_FILE || defined __CYGWIN__
#   undef HAVE_ACL_EXTENDED_FILE
130 131 132 133
#   define HAVE_ACL_EXTENDED_FILE false
#   define acl_extended_file(name) (-1)
#  endif

Paul Eggert's avatar
Paul Eggert committed
134 135
#  if ! defined HAVE_ACL_FROM_MODE && ! defined HAVE_ACL_FROM_TEXT
#   define acl_from_mode (NULL)
136 137
#  endif

Paul Eggert's avatar
Paul Eggert committed
138
/* Set to 0 if a file's mode is stored independently from the ACL.  */
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
#  if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
#   define MODE_INSIDE_ACL 0
#  endif

/* Return the number of entries in ACL.
   Return -1 and set errno upon failure to determine it.  */
/* Define a replacement for acl_entries if needed. (Only Linux has it.)  */
#  if !HAVE_ACL_ENTRIES
#   define acl_entries rpl_acl_entries
extern int acl_entries (acl_t);
#  endif

#  if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
   Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial.  */
extern int acl_extended_nontrivial (acl_t);
#  else
/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
   Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
   Return -1 and set errno upon failure to determine it.  */
extern int acl_access_nontrivial (acl_t);
Paul Eggert's avatar
Paul Eggert committed
162 163 164 165 166 167

/* ACL is an ACL, from a file, stored as type ACL_TYPE_DEFAULT.
   Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
   Return -1 and set errno upon failure to determine it.  */
extern int acl_default_nontrivial (acl_t);
168 169
#  endif

Paul Eggert's avatar
Paul Eggert committed
170
# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
171

Paul Eggert's avatar
Paul Eggert committed
172
/* Set to 0 if a file's mode is stored independently from the ACL.  */
173 174 175 176 177 178
#  if defined __CYGWIN__ /* Cygwin */
#   define MODE_INSIDE_ACL 0
#  endif

/* Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
Paul Eggert's avatar
Paul Eggert committed
179
extern int acl_nontrivial (int count, aclent_t *entries) _GL_ATTRIBUTE_PURE;
180 181 182 183 184 185

#  ifdef ACE_GETACL /* Solaris 10 */

/* Test an ACL retrieved with ACE_GETACL.
   Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
Paul Eggert's avatar
Paul Eggert committed
186
extern int acl_ace_nontrivial (int count, ace_t *entries) _GL_ATTRIBUTE_PURE;
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

/* Definitions for when the built executable is executed on Solaris 10
   (newer version) or Solaris 11.  */
/* For a_type.  */
#   define OLD_ALLOW 0
#   define OLD_DENY  1
#   define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
#   define NEW_ACE_ACCESS_DENIED_ACE_TYPE  1 /* replaces DENY */
/* For a_flags.  */
#   define OLD_ACE_OWNER            0x0100
#   define OLD_ACE_GROUP            0x0200
#   define OLD_ACE_OTHER            0x0400
#   define NEW_ACE_OWNER            0x1000
#   define NEW_ACE_GROUP            0x2000
#   define NEW_ACE_IDENTIFIER_GROUP 0x0040
#   define NEW_ACE_EVERYONE         0x4000
/* For a_access_mask.  */
#   define NEW_ACE_READ_DATA         0x001 /* corresponds to 'r' */
#   define NEW_ACE_WRITE_DATA        0x002 /* corresponds to 'w' */
#   define NEW_ACE_APPEND_DATA       0x004
#   define NEW_ACE_READ_NAMED_ATTRS  0x008
#   define NEW_ACE_WRITE_NAMED_ATTRS 0x010
#   define NEW_ACE_EXECUTE           0x020
#   define NEW_ACE_DELETE_CHILD      0x040
#   define NEW_ACE_READ_ATTRIBUTES   0x080
#   define NEW_ACE_WRITE_ATTRIBUTES  0x100
#   define NEW_ACE_DELETE          0x10000
#   define NEW_ACE_READ_ACL        0x20000
#   define NEW_ACE_WRITE_ACL       0x40000
#   define NEW_ACE_WRITE_OWNER     0x80000
#   define NEW_ACE_SYNCHRONIZE    0x100000

#  endif

# elif HAVE_GETACL /* HP-UX */

/* Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
Paul Eggert's avatar
Paul Eggert committed
225
extern int acl_nontrivial (int count, struct acl_entry *entries);
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

#  if HAVE_ACLV_H /* HP-UX >= 11.11 */

/* Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
extern int aclv_nontrivial (int count, struct acl *entries);

#  endif

# elif HAVE_ACLX_GET && 0 /* AIX */

/* TODO */

# elif HAVE_STATACL /* older AIX */

/* Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
extern int acl_nontrivial (struct acl *a);

# elif HAVE_ACLSORT /* NonStop Kernel */

/* Return 1 if the given ACL is non-trivial.
   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
extern int acl_nontrivial (int count, struct acl *entries);

# endif

Paul Eggert's avatar
Paul Eggert committed
253 254 255 256 257
/* Set to 1 if a file's mode is implicit by the ACL.  */
# ifndef MODE_INSIDE_ACL
#  define MODE_INSIDE_ACL 1
# endif

258 259
#endif

Paul Eggert's avatar
Paul Eggert committed
260 261
struct permission_context {
  mode_t mode;
Paul Eggert's avatar
Paul Eggert committed
262
#if USE_ACL
Paul Eggert's avatar
Paul Eggert committed
263
# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
Paul Eggert's avatar
Paul Eggert committed
264 265 266 267 268 269
  acl_t acl;
#  if !HAVE_ACL_TYPE_EXTENDED
  acl_t default_acl;
#  endif
  bool acls_not_supported;

Paul Eggert's avatar
Paul Eggert committed
270
# elif defined GETACL /* Solaris, Cygwin < 2.5 */
Paul Eggert's avatar
Paul Eggert committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
  int count;
  aclent_t *entries;
#  ifdef ACE_GETACL
  int ace_count;
  ace_t *ace_entries;
#  endif

# elif HAVE_GETACL /* HP-UX */
  struct acl_entry entries[NACLENTRIES];
  int count;
#  if HAVE_ACLV_H
  struct acl aclv_entries[NACLVENTRIES];
  int aclv_count;
#  endif

# elif HAVE_STATACL /* older AIX */
  union { struct acl a; char room[4096]; } u;
  bool have_u;

# elif HAVE_ACLSORT /* NonStop Kernel */
  struct acl entries[NACLENTRIES];
  int count;

# endif
#endif
};

int get_permissions (const char *, int, mode_t, struct permission_context *);
int set_permissions (struct permission_context *, const char *, int);
Paul Eggert's avatar
Paul Eggert committed
300
void free_permission_context (struct permission_context *);
Paul Eggert's avatar
Paul Eggert committed
301

302
_GL_INLINE_HEADER_END