1 /* acl.c - access control lists
3 Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
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 2, or (at your option)
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 Written by Paul Eggert and Andreas Gruenbacher. */
28 #include <sys/types.h>
31 # define S_ISLNK(Mode) 0
34 #ifdef HAVE_ACL_LIBACL_H
35 # include <acl/libacl.h>
52 # define _(Text) gettext (Text)
58 # define HAVE_FCHMOD false
59 # define fchmod(fd, mode) (-1)
62 /* POSIX 1003.1e (draft 17) */
63 #ifndef HAVE_ACL_GET_FD
64 # define HAVE_ACL_GET_FD false
65 # define acl_get_fd(fd) (NULL)
68 /* POSIX 1003.1e (draft 17) */
69 #ifndef HAVE_ACL_SET_FD
70 # define HAVE_ACL_SET_FD false
71 # define acl_set_fd(fd, acl) (-1)
75 #ifndef HAVE_ACL_EXTENDED_FILE
76 # define HAVE_ACL_EXTENDED_FILE false
77 # define acl_extended_file(name) (-1)
81 #ifndef HAVE_ACL_FROM_MODE
82 # define HAVE_ACL_FROM_MODE false
83 # define acl_from_mode(mode) (NULL)
86 /* We detect presence of POSIX 1003.1e (draft 17 -- abandoned) support
87 by checking for HAVE_ACL_GET_FILE, HAVE_ACL_SET_FILE, and HAVE_ACL_FREE.
88 Systems that have acl_get_file, acl_set_file, and acl_free must also
89 have acl_to_text, acl_from_text, and acl_delete_def_file (all defined
90 in the draft); systems that don't would hit #error statements here. */
92 #if USE_ACL && HAVE_ACL_GET_FILE && !HAVE_ACL_ENTRIES
93 # ifndef HAVE_ACL_TO_TEXT
94 # error Must have acl_to_text (see POSIX 1003.1e draft 17).
97 /* Return the number of entries in ACL. Linux implements acl_entries
98 as a more efficient extension than using this workaround. */
101 acl_entries (acl_t acl)
103 char *text = acl_to_text (acl, NULL), *t;
107 for (entries = 0, t = text; ; t++, entries++) {
108 t = strchr (t, '\n');
117 /* If DESC is a valid file descriptor use fchmod to change the
118 file's mode to MODE on systems that have fchown. On systems
119 that don't have fchown and if DESC is invalid, use chown on
123 chmod_or_fchmod (const char *name, int desc, mode_t mode)
125 if (HAVE_FCHMOD && desc != -1)
126 return fchmod (desc, mode);
128 return chmod (name, mode);
131 /* Return 1 if NAME has a nontrivial access control list, 0 if
132 NAME only has no or a base access control list, and -1 on
133 error. SB must be set to the stat buffer of FILE. */
136 file_has_acl (char const *name, struct stat const *sb)
138 #if USE_ACL && HAVE_ACL && defined GETACLCNT
139 /* This implementation should work on recent-enough versions of HP-UX,
140 Solaris, and Unixware. */
142 # ifndef MIN_ACL_ENTRIES
143 # define MIN_ACL_ENTRIES 4
146 if (! S_ISLNK (sb->st_mode))
148 int n = acl (name, GETACLCNT, 0, NULL);
149 return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n);
151 #elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
152 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
154 if (! S_ISLNK (sb->st_mode))
158 if (HAVE_ACL_EXTENDED_FILE)
159 ret = acl_extended_file (name);
162 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
165 ret = (3 < acl_entries (acl));
167 if (ret == 0 && S_ISDIR (sb->st_mode))
169 acl = acl_get_file (name, ACL_TYPE_DEFAULT);
172 ret = (0 < acl_entries (acl));
183 return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1;
188 /* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's
189 source/lib/sysacls.c file for fix-related ideas. */
194 /* Copy access control lists from one file to another. If SOURCE_DESC is
195 a valid file descriptor, use file descriptor operations, else use
196 filename based operations on SRC_NAME. Likewise for DEST_DESC and
198 If access control lists are not available, fchmod the target file to
199 MODE. Also sets the non-permission bits of the destination file
200 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
201 System call return value semantics. */
204 copy_acl (const char *src_name, int source_desc, const char *dst_name,
205 int dest_desc, mode_t mode)
209 #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
210 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
213 if (HAVE_ACL_GET_FD && source_desc != -1)
214 acl = acl_get_fd (source_desc);
216 acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
219 if (errno == ENOSYS || errno == ENOTSUP)
220 return set_acl (dst_name, dest_desc, mode);
223 error (0, errno, "%s", quote (src_name));
228 if (HAVE_ACL_SET_FD && dest_desc != -1)
229 ret = acl_set_fd (dest_desc, acl);
231 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
234 int saved_errno = errno;
236 if (errno == ENOSYS || errno == ENOTSUP)
238 int n = acl_entries (acl);
243 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
249 chmod_or_fchmod (dst_name, dest_desc, mode);
254 chmod_or_fchmod (dst_name, dest_desc, mode);
256 error (0, saved_errno, _("preserving permissions for %s"),
263 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
265 /* We did not call chmod so far, so the special bits have not yet
268 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
270 error (0, errno, _("preserving permissions for %s"),
278 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
281 error (0, errno, "%s", quote (src_name));
285 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
287 error (0, errno, _("preserving permissions for %s"),
297 ret = chmod_or_fchmod (dst_name, dest_desc, mode);
299 error (0, errno, _("preserving permissions for %s"), quote (dst_name));
304 /* Set the access control lists of a file. If DESC is a valid file
305 descriptor, use file descriptor operations where available, else use
306 filename based operations on NAME. If access control lists are not
307 available, fchmod the target file to MODE. Also sets the
308 non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
309 to those from MODE if any are set. System call return value
313 set_acl (char const *name, int desc, mode_t mode)
315 #if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
316 /* POSIX 1003.1e draft 17 (abandoned) specific version. */
318 /* We must also have have_acl_from_text and acl_delete_def_file.
319 (acl_delete_def_file could be emulated with acl_init followed
320 by acl_set_file, but acl_set_file with an empty acl is
323 # ifndef HAVE_ACL_FROM_TEXT
324 # error Must have acl_from_text (see POSIX 1003.1e draft 17).
326 # ifndef HAVE_ACL_DELETE_DEF_FILE
327 # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
333 if (HAVE_ACL_FROM_MODE)
335 acl = acl_from_mode (mode);
338 error (0, errno, "%s", quote (name));
344 char acl_text[] = "u::---,g::---,o::---";
346 if (mode & S_IRUSR) acl_text[ 3] = 'r';
347 if (mode & S_IWUSR) acl_text[ 4] = 'w';
348 if (mode & S_IXUSR) acl_text[ 5] = 'x';
349 if (mode & S_IRGRP) acl_text[10] = 'r';
350 if (mode & S_IWGRP) acl_text[11] = 'w';
351 if (mode & S_IXGRP) acl_text[12] = 'x';
352 if (mode & S_IROTH) acl_text[17] = 'r';
353 if (mode & S_IWOTH) acl_text[18] = 'w';
354 if (mode & S_IXOTH) acl_text[19] = 'x';
356 acl = acl_from_text (acl_text);
359 error (0, errno, "%s", quote (name));
363 if (HAVE_ACL_SET_FD && desc != -1)
364 ret = acl_set_fd (desc, acl);
366 ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
369 int saved_errno = errno;
372 if (errno == ENOTSUP || errno == ENOSYS)
374 if (chmod_or_fchmod (name, desc, mode) != 0)
379 error (0, saved_errno, _("setting permissions for %s"), quote (name));
385 if (S_ISDIR (mode) && acl_delete_def_file (name))
387 error (0, errno, _("setting permissions for %s"), quote (name));
391 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
393 /* We did not call chmod so far, so the special bits have not yet
396 if (chmod_or_fchmod (name, desc, mode))
398 error (0, errno, _("preserving permissions for %s"), quote (name));
404 int ret = chmod_or_fchmod (name, desc, mode);
406 error (0, errno, _("setting permissions for %s"), quote (name));