• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/
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
31int
32chmod_or_fchmod (const char *name, int desc, mode_t mode)
33{
34  if (HAVE_FCHMOD && desc != -1)
35    return fchmod (desc, mode);
36  else
37    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   DEST_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   System call return value semantics.  */
48
49int
50copy_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#else
148  ret = chmod_or_fchmod (dst_name, dest_desc, mode);
149  if (ret != 0)
150    error (0, errno, _("preserving permissions for %s"), quote (dst_name));
151  return ret;
152#endif
153}
154
155/* Set the access control lists of a file. If DESC is a valid file
156   descriptor, use file descriptor operations where available, else use
157   filename based operations on NAME.  If access control lists are not
158   available, fchmod the target file to MODE.  Also sets the
159   non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
160   to those from MODE if any are set.  System call return value
161   semantics.  */
162
163int
164set_acl (char const *name, int desc, mode_t mode)
165{
166#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
167  /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
168
169  /* We must also have have_acl_from_text and acl_delete_def_file.
170     (acl_delete_def_file could be emulated with acl_init followed
171      by acl_set_file, but acl_set_file with an empty acl is
172      unspecified.)  */
173
174# ifndef HAVE_ACL_FROM_TEXT
175#  error Must have acl_from_text (see POSIX 1003.1e draft 17).
176# endif
177# ifndef HAVE_ACL_DELETE_DEF_FILE
178#  error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
179# endif
180
181  acl_t acl;
182  int ret;
183
184  if (HAVE_ACL_FROM_MODE)
185    {
186      acl = acl_from_mode (mode);
187      if (!acl)
188	{
189	  error (0, errno, "%s", quote (name));
190	  return -1;
191	}
192    }
193  else
194    {
195      char acl_text[] = "u::---,g::---,o::---";
196
197      if (mode & S_IRUSR) acl_text[ 3] = 'r';
198      if (mode & S_IWUSR) acl_text[ 4] = 'w';
199      if (mode & S_IXUSR) acl_text[ 5] = 'x';
200      if (mode & S_IRGRP) acl_text[10] = 'r';
201      if (mode & S_IWGRP) acl_text[11] = 'w';
202      if (mode & S_IXGRP) acl_text[12] = 'x';
203      if (mode & S_IROTH) acl_text[17] = 'r';
204      if (mode & S_IWOTH) acl_text[18] = 'w';
205      if (mode & S_IXOTH) acl_text[19] = 'x';
206
207      acl = acl_from_text (acl_text);
208      if (!acl)
209	{
210	  error (0, errno, "%s", quote (name));
211	  return -1;
212	}
213    }
214  if (HAVE_ACL_SET_FD && desc != -1)
215    ret = acl_set_fd (desc, acl);
216  else
217    ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
218  if (ret != 0)
219    {
220      int saved_errno = errno;
221      acl_free (acl);
222
223      if (ACL_NOT_WELL_SUPPORTED (errno))
224	{
225	  if (chmod_or_fchmod (name, desc, mode) != 0)
226	    saved_errno = errno;
227	  else
228	    return 0;
229	}
230      error (0, saved_errno, _("setting permissions for %s"), quote (name));
231      return -1;
232    }
233  else
234    acl_free (acl);
235
236  if (S_ISDIR (mode) && acl_delete_def_file (name))
237    {
238      error (0, errno, _("setting permissions for %s"), quote (name));
239      return -1;
240    }
241
242  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
243    {
244      /* We did not call chmod so far, so the special bits have not yet
245         been set.  */
246
247      if (chmod_or_fchmod (name, desc, mode))
248	{
249	  error (0, errno, _("preserving permissions for %s"), quote (name));
250	  return -1;
251	}
252    }
253  return 0;
254#else
255   int ret = chmod_or_fchmod (name, desc, mode);
256   if (ret)
257     error (0, errno, _("setting permissions for %s"), quote (name));
258   return ret;
259#endif
260}
261