1 /* acl.c - access control lists
3 Copyright (C) 2002, 2003, 2005, 2006 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. */
26 #include <sys/types.h>
29 # define S_ISLNK(Mode) 0
32 #ifdef HAVE_ACL_LIBACL_H
33 # include <acl/libacl.h>
50 # define _(Text) gettext (Text)
56 # define HAVE_FCHMOD false
57 # define fchmod(fd, mode) (-1)
60 /* POSIX 1003.1e (draft 17) */
61 #ifndef HAVE_ACL_GET_FD
62 # define HAVE_ACL_GET_FD false
63 # define acl_get_fd(fd) (NULL)
66 /* POSIX 1003.1e (draft 17) */
67 #ifndef HAVE_ACL_SET_FD
68 # define HAVE_ACL_SET_FD false
69 # define acl_set_fd(fd, acl) (-1)
73 #ifndef HAVE_ACL_EXTENDED_FILE
74 # define HAVE_ACL_EXTENDED_FILE false
75 # define acl_extended_file(name) (-1)
79 #ifndef HAVE_ACL_FROM_MODE
80 # define HAVE_ACL_FROM_MODE false
81 # define acl_from_mode(mode) (NULL)
84 /* We detect presence of POSIX 1003.1e (draft 17 -- abandoned) support
85 by checking for HAVE_ACL_GET_FILE, HAVE_ACL_SET_FILE, and HAVE_ACL_FREE.
86 Systems that have acl_get_file, acl_set_file, and acl_free must also
87 have acl_to_text, acl_from_text, and acl_delete_def_file (all defined
88 in the draft); systems that don't would hit #error statements here. */
90 #if USE_ACL && HAVE_ACL_GET_FILE && !HAVE_ACL_ENTRIES
91 # ifndef HAVE_ACL_TO_TEXT
92 # error Must have acl_to_text (see POSIX 1003.1e draft 17).
95 /* Return the number of entries in ACL. Linux implements acl_entries
96 as a more efficient extension than using this workaround. */
99 acl_entries (acl_t acl)
101 char *text = acl_to_text (acl, NULL), *t;
105 for (entries = 0, t = text; ; t++, entries++) {
106 t = strchr (t, '\n');
115 /* If DESC is a valid file descriptor use fchmod to change the
116 file's mode to MODE on systems that have fchown. On systems
117 that don't have fchown and if DESC is invalid, use chown on
121 chmod_or_fchmod (const char *name, int desc, mode_t mode)
123 if (HAVE_FCHMOD && desc != -1)
124 return fchmod (desc, mode);
126 return chmod (name, mode);
129 /* Return 1 if NAME has a nontrivial access control list, 0 if
130 NAME only has no or a base access control list, and -1 on
131 error. SB must be set to the stat buffer of FILE. */
134 file_has_acl (char const *name, struct stat const *sb)
136 #if USE_ACL && HAVE_ACL && defined GETACLCNT
137 /* This implementation should work on recent-enough versions of HP-UX,
138 Solaris, and Unixware. */
140 # ifndef MIN_ACL_ENTRIES
141 # define MIN_ACL_ENTRIES 4
144 if (! S_ISLNK (sb->st_mode))
146 int n = acl (name, GETACLCNT, 0, NULL);
147 return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n);
149 #elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
150 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
152 if (! S_ISLNK (sb->st_mode))
156 if (HAVE_ACL_EXTENDED_FILE)
157 ret = acl_extended_file (name);
160 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
163 ret = (3 < acl_entries (acl));
165 if (ret == 0 && S_ISDIR (sb->st_mode))
167 acl = acl_get_file (name, ACL_TYPE_DEFAULT);
170 ret = (0 < acl_entries (acl));
181 return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1;
186 /* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's
187 source/lib/sysacls.c file for fix-related ideas. */
192 /* Copy access control lists from one file to another. If SOURCE_DESC is
193 a valid file descriptor, use file descriptor operations, else use
194 filename based operations on SRC_NAME. Likewise for DEST_DESC and
196 If access control lists are not available, fchmod the target file to
197 MODE. Also sets the non-permission bits of the destination file
198 (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
199 System call return value semantics. */
202 copy_acl (const char *src_name, int source_desc, const char *dst_name,
203 int dest_desc, mode_t mode)
207 #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
208 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
211 if (HAVE_ACL_GET_FD && source_desc != -1)
212 acl = acl_get_fd (source_desc);
214 acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
217 if (errno == ENOSYS || errno == ENOTSUP)
218 return set_acl (dst_name, dest_desc, mode);
221 error (0, errno, "%s", quote (src_name));
226 if (HAVE_ACL_SET_FD && dest_desc != -1)
227 ret = acl_set_fd (dest_desc, acl);
229 ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
232 int saved_errno = errno;
234 if (errno == ENOSYS || errno == ENOTSUP)
236 int n = acl_entries (acl);
241 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
247 chmod_or_fchmod (dst_name, dest_desc, mode);
252 chmod_or_fchmod (dst_name, dest_desc, mode);
254 error (0, saved_errno, _("preserving permissions for %s"),
261 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
263 /* We did not call chmod so far, so the special bits have not yet
266 if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
268 error (0, errno, _("preserving permissions for %s"),
276 acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
279 error (0, errno, "%s", quote (src_name));
283 if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
285 error (0, errno, _("preserving permissions for %s"),
295 ret = chmod_or_fchmod (dst_name, dest_desc, mode);
297 error (0, errno, _("preserving permissions for %s"), quote (dst_name));
302 /* Set the access control lists of a file. If DESC is a valid file
303 descriptor, use file descriptor operations where available, else use
304 filename based operations on NAME. If access control lists are not
305 available, fchmod the target file to MODE. Also sets the
306 non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
307 to those from MODE if any are set. System call return value
311 set_acl (char const *name, int desc, mode_t mode)
313 #if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
314 /* POSIX 1003.1e draft 17 (abandoned) specific version. */
316 /* We must also have have_acl_from_text and acl_delete_def_file.
317 (acl_delete_def_file could be emulated with acl_init followed
318 by acl_set_file, but acl_set_file with an empty acl is
321 # ifndef HAVE_ACL_FROM_TEXT
322 # error Must have acl_from_text (see POSIX 1003.1e draft 17).
324 # ifndef HAVE_ACL_DELETE_DEF_FILE
325 # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
331 if (HAVE_ACL_FROM_MODE)
333 acl = acl_from_mode (mode);
336 error (0, errno, "%s", quote (name));
342 char acl_text[] = "u::---,g::---,o::---";
344 if (mode & S_IRUSR) acl_text[ 3] = 'r';
345 if (mode & S_IWUSR) acl_text[ 4] = 'w';
346 if (mode & S_IXUSR) acl_text[ 5] = 'x';
347 if (mode & S_IRGRP) acl_text[10] = 'r';
348 if (mode & S_IWGRP) acl_text[11] = 'w';
349 if (mode & S_IXGRP) acl_text[12] = 'x';
350 if (mode & S_IROTH) acl_text[17] = 'r';
351 if (mode & S_IWOTH) acl_text[18] = 'w';
352 if (mode & S_IXOTH) acl_text[19] = 'x';
354 acl = acl_from_text (acl_text);
357 error (0, errno, "%s", quote (name));
361 if (HAVE_ACL_SET_FD && desc != -1)
362 ret = acl_set_fd (desc, acl);
364 ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
367 int saved_errno = errno;
370 if (errno == ENOTSUP || errno == ENOSYS)
372 if (chmod_or_fchmod (name, desc, mode) != 0)
377 error (0, saved_errno, _("setting permissions for %s"), quote (name));
383 if (S_ISDIR (mode) && acl_delete_def_file (name))
385 error (0, errno, _("setting permissions for %s"), quote (name));
389 if (mode & (S_ISUID | S_ISGID | S_ISVTX))
391 /* We did not call chmod so far, so the special bits have not yet
394 if (chmod_or_fchmod (name, desc, mode))
396 error (0, errno, _("preserving permissions for %s"), quote (name));
402 int ret = chmod_or_fchmod (name, desc, mode);
404 error (0, errno, _("setting permissions for %s"), quote (name));