1 /*
2 * Copyright (c) 2001-2002 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it would 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, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "config.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <getopt.h>
25 #include <libgen.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <dirent.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/acl.h>
32 #include <acl/libacl.h>
33 #include "misc.h"
34
35 static int acl_delete_file (const char * path, acl_type_t type);
36 static int list_acl(char *file);
37 static int set_acl(acl_t acl, acl_t dacl, const char *fname);
38 static int walk_dir(acl_t acl, acl_t dacl, const char *fname);
39
40 static char *program;
41 static int rflag;
42
43 static void
44 usage(void)
45 {
46 fprintf(stderr, _("Usage:\n"));
47 fprintf(stderr, _("\t%s acl pathname...\n"), program);
48 fprintf(stderr, _("\t%s -b acl dacl pathname...\n"), program);
49 fprintf(stderr, _("\t%s -d dacl pathname...\n"), program);
50 fprintf(stderr, _("\t%s -R pathname...\n"), program);
51 fprintf(stderr, _("\t%s -D pathname...\n"), program);
52 fprintf(stderr, _("\t%s -B pathname...\n"), program);
53 fprintf(stderr, _("\t%s -l pathname...\t[not IRIX compatible]\n"),
54 program);
55 fprintf(stderr, _("\t%s -r pathname...\t[not IRIX compatible]\n"),
56 program);
57 exit(1);
58 }
59
60 int
61 main(int argc, char *argv[])
62 {
63 char *file;
64 int switch_flag = 0; /* ensure only one switch is used */
65 int args_required = 2;
66 int failed = 0; /* exit status */
67 int c; /* For use by getopt(3) */
68 int dflag = 0; /* a Default ACL is desired */
69 int bflag = 0; /* a both ACLs are desired */
70 int Rflag = 0; /* set to true to remove an acl */
71 int Dflag = 0; /* set to true to remove default acls */
72 int Bflag = 0; /* set to true to remove both acls */
73 int lflag = 0; /* set to true to list acls */
74 acl_t acl = NULL; /* File ACL */
75 acl_t dacl = NULL; /* Directory Default ACL */
76
77 program = basename(argv[0]);
78
79 setlocale(LC_CTYPE, "");
80 setlocale(LC_MESSAGES, "");
81 bindtextdomain(PACKAGE, LOCALEDIR);
82 textdomain(PACKAGE);
83
84 /* parse arguments */
85 while ((c = getopt(argc, argv, "bdlRDBr")) != -1) {
86 if (switch_flag)
87 usage();
88 switch_flag = 1;
89
90 switch (c) {
91 case 'b':
92 bflag = 1;
93 args_required = 3;
94 break;
95 case 'd':
96 dflag = 1;
97 args_required = 2;
98 break;
99 case 'R':
100 Rflag = 1;
101 args_required = 1;
102 break;
103 case 'D':
104 Dflag = 1;
105 args_required = 1;
106 break;
107 case 'B':
108 Bflag = 1;
109 args_required = 1;
110 break;
111 case 'l':
112 lflag = 1;
113 args_required = 1;
114 break;
115 case 'r':
116 rflag = 1;
117 args_required = 1;
118 break;
119 default:
120 usage();
121 break;
122 }
123 }
124
125 /* if not enough arguments quit */
126 if ((argc - optind) < args_required)
127 usage();
128
129 /* list the acls */
130 if (lflag) {
131 for (; optind < argc; optind++) {
132 file = argv[optind];
133 if (!list_acl(file))
134 failed++;
135 }
136 return(failed);
137 }
138
139 /* remove the acls */
140 if (Rflag || Dflag || Bflag) {
141 for (; optind < argc; optind++) {
142 file = argv[optind];
143 if (!Dflag &&
144 (acl_delete_file(file, ACL_TYPE_ACCESS) == -1)) {
145 fprintf(stderr, _(
146 "%s: error removing access acl on \"%s\": %s\n"),
147 program, file, strerror(errno));
148 failed++;
149 }
150 if (!Rflag &&
151 (acl_delete_file(file, ACL_TYPE_DEFAULT) == -1)) {
152 fprintf(stderr, _(
153 "%s: error removing default acl on \"%s\": %s\n"),
154 program, file, strerror(errno));
155 failed++;
156 }
157 }
158 return(failed);
159 }
160
161 /* file access acl */
162 if (! dflag) {
163 acl = acl_from_text(argv[optind]);
164 failed = acl_check(acl, &c);
165 if (failed < 0) {
166 fprintf(stderr, "%s: %s - %s\n",
167 program, argv[optind], strerror(errno));
168 return 1;
169 }
170 else if (failed > 0) {
171 fprintf(stderr, _(
172 "%s: access ACL '%s': %s at entry %d\n"),
173 program, argv[optind], acl_error(failed), c);
174 return 1;
175 }
176 optind++;
177 }
178
179
180 /* directory default acl */
181 if (bflag || dflag) {
182 dacl = acl_from_text(argv[optind]);
183 failed = acl_check(dacl, &c);
184 if (failed < 0) {
185 fprintf(stderr, "%s: %s - %s\n",
186 program, argv[optind], strerror(errno));
187 return 1;
188 }
189 else if (failed > 0) {
190 fprintf(stderr, _(
191 "%s: access ACL '%s': %s at entry %d\n"),
192 program, argv[optind], acl_error(failed), c);
193 return 1;
194 }
195 optind++;
196 }
197
198 /* place acls on files */
199 for (; optind < argc; optind++)
200 failed += set_acl(acl, dacl, argv[optind]);
201
202 if (acl)
203 acl_free(acl);
204 if (dacl)
205 acl_free(dacl);
206
207 return(failed);
208 }
209
210 /*
211 * deletes an access acl or directory default acl if one exists
212 */
213 static int
214 acl_delete_file(const char *path, acl_type_t type)
215 {
216 int error = 0;
217
218 /* converts access ACL to a minimal ACL */
219 if (type == ACL_TYPE_ACCESS) {
220 acl_t acl;
221 acl_entry_t entry;
222 acl_tag_t tag;
223
224 acl = acl_get_file(path, ACL_TYPE_ACCESS);
225 if (!acl)
226 return -1;
227 error = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
228 while (error == 1) {
229 acl_get_tag_type(entry, &tag);
230 switch(tag) {
231 case ACL_USER:
232 case ACL_GROUP:
233 case ACL_MASK:
234 acl_delete_entry(acl, entry);
235 break;
236 }
237 error = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
238 }
239 if (!error)
240 error = acl_set_file(path, ACL_TYPE_ACCESS, acl);
241 } else
242 error = acl_delete_def_file(path);
243 return(error);
244 }
245
246 /*
247 * lists the acl for a file/dir in short text form
248 * return 0 on failure
249 * return 1 on success
250 */
251 static int
252 list_acl(char *file)
253 {
254 acl_t acl = NULL;
255 acl_t dacl = NULL;
256 char *acl_text, *dacl_text = NULL;
257
258 if ((acl = acl_get_file(file, ACL_TYPE_ACCESS)) == NULL) {
259 fprintf(stderr, _("%s: cannot get access ACL on '%s': %s\n"),
260 program, file, strerror(errno));
261 return 0;
262 }
263 if ((dacl = acl_get_file(file, ACL_TYPE_DEFAULT)) == NULL &&
264 (errno != EACCES)) { /* EACCES given if not a directory */
265 fprintf(stderr, _("%s: cannot get default ACL on '%s': %s\n"),
266 program, file, strerror(errno));
267 return 0;
268 }
269 acl_text = acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE);
270 if (acl_text == NULL) {
271 fprintf(stderr, _("%s: cannot get access ACL text on "
272 "'%s': %s\n"), program, file, strerror(errno));
273 return 0;
274 }
275 if (acl_entries(dacl) > 0) {
276 dacl_text = acl_to_any_text(dacl, NULL, ',', TEXT_ABBREVIATE);
277 if (dacl_text == NULL) {
278 fprintf(stderr, _("%s: cannot get default ACL text on "
279 "'%s': %s\n"), program, file, strerror(errno));
280 return 0;
281 }
282 }
283 if (dacl_text) {
284 printf("%s [%s/%s]\n", file, acl_text, dacl_text);
285 acl_free(dacl_text);
286 } else
287 printf("%s [%s]\n", file, acl_text);
288 acl_free(acl_text);
289 acl_free(acl);
290 acl_free(dacl);
291 return 1;
292 }
293
294 static int
295 set_acl(acl_t acl, acl_t dacl, const char *fname)
296 {
297 int failed = 0;
298
299 if (rflag)
300 failed += walk_dir(acl, dacl, fname);
301
302 /* set regular acl */
303 if (acl && acl_set_file(fname, ACL_TYPE_ACCESS, acl) == -1) {
304 fprintf(stderr, _("%s: cannot set access acl on \"%s\": %s\n"),
305 program, fname, strerror(errno));
306 failed++;
307 }
308 /* set default acl */
309 if (dacl && acl_set_file(fname, ACL_TYPE_DEFAULT, dacl) == -1) {
310 fprintf(stderr, _("%s: cannot set default acl on \"%s\": %s\n"),
311 program, fname, strerror(errno));
312 failed++;
313 }
314
315 return(failed);
316 }
317
318 static int
319 walk_dir(acl_t acl, acl_t dacl, const char *fname)
320 {
321 int failed = 0;
322 DIR *dir;
323 struct dirent64 *d;
324 char *name;
325
326 if ((dir = opendir(fname)) == NULL) {
327 if (errno != ENOTDIR) {
328 fprintf(stderr, _("%s: opendir failed: %s\n"),
329 program, strerror(errno));
330 return(1);
331 }
332 return(0); /* got a file, not an error */
333 }
334
335 while ((d = readdir64(dir)) != NULL) {
336 /* skip "." and ".." entries */
337 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
338 continue;
339
340 name = malloc(strlen(fname) + strlen(d->d_name) + 2);
341 if (name == NULL) {
342 fprintf(stderr, _("%s: malloc failed: %s\n"),
343 program, strerror(errno));
344 exit(1);
345 }
346 sprintf(name, "%s/%s", fname, d->d_name);
347
348 failed += set_acl(acl, dacl, name);
349 free(name);
350 }
351 closedir(dir);
352
353 return(failed);
354 }