Lines 39-44
__FBSDID("$FreeBSD$");
Link Here
|
39 |
#include <stdlib.h> |
39 |
#include <stdlib.h> |
40 |
#include <string.h> |
40 |
#include <string.h> |
41 |
#include <unistd.h> |
41 |
#include <unistd.h> |
|
|
42 |
#include <ftw.h> |
42 |
|
43 |
|
43 |
#include "setfacl.h" |
44 |
#include "setfacl.h" |
44 |
|
45 |
|
Lines 70-77
uint have_mask;
Link Here
|
70 |
uint need_mask; |
71 |
uint need_mask; |
71 |
uint have_stdin; |
72 |
uint have_stdin; |
72 |
uint n_flag; |
73 |
uint n_flag; |
|
|
74 |
static int h_flag; |
75 |
static int R_flag; |
76 |
static unsigned int carried_error; |
77 |
static acl_type_t acl_type; |
73 |
|
78 |
|
74 |
static void add_filename(const char *filename); |
79 |
static void add_filename(const char *filename); |
|
|
80 |
static acl_t sanitize_inheritance(const struct stat *sb, acl_t acl); |
81 |
static int walk_path(const char *path, const struct stat *sb, int flag, struct FTW *ftwp); |
75 |
static void usage(void); |
82 |
static void usage(void); |
76 |
|
83 |
|
77 |
static void |
84 |
static void |
Lines 88-98
add_filename(const char *filename)
Link Here
|
88 |
TAILQ_INSERT_TAIL(&filelist, file, next); |
95 |
TAILQ_INSERT_TAIL(&filelist, file, next); |
89 |
} |
96 |
} |
90 |
|
97 |
|
|
|
98 |
static acl_t |
99 |
sanitize_inheritance(const struct stat *sb, acl_t acl) |
100 |
{ |
101 |
acl_t acl_new; |
102 |
acl_entry_t acl_entry; |
103 |
acl_flagset_t acl_flagset; |
104 |
int acl_brand, entry_id; |
105 |
|
106 |
acl_get_brand_np(acl, &acl_brand); |
107 |
if (acl_brand != ACL_BRAND_NFS4) |
108 |
return (acl); |
109 |
|
110 |
if (S_ISDIR(sb->st_mode) != 0) |
111 |
return (acl); |
112 |
|
113 |
acl_new = acl_dup(acl); |
114 |
if (acl_new == (acl_t)NULL) |
115 |
return ((acl_t)NULL); |
116 |
|
117 |
entry_id = ACL_FIRST_ENTRY; |
118 |
while (acl_get_entry(acl_new, entry_id, &acl_entry) == 1) { |
119 |
entry_id = ACL_NEXT_ENTRY; |
120 |
acl_get_flagset_np(acl_entry, &acl_flagset); |
121 |
if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY)) { |
122 |
acl_delete_entry(acl_new, acl_entry); |
123 |
continue; |
124 |
} |
125 |
acl_delete_flag_np(acl_flagset, ACL_ENTRY_FILE_INHERIT |
126 |
| ACL_ENTRY_DIRECTORY_INHERIT |
127 |
| ACL_ENTRY_NO_PROPAGATE_INHERIT); |
128 |
} |
129 |
|
130 |
return acl_new; |
131 |
} |
132 |
|
133 |
static int |
134 |
walk_path(const char *path, const struct stat *sb, int flag, struct FTW *ftwp __unused) |
135 |
{ |
136 |
acl_t acl, acl_backup=NULL; |
137 |
acl_entry_t unused_entry; |
138 |
struct sf_entry *entry; |
139 |
unsigned int local_error; |
140 |
int ret; |
141 |
|
142 |
local_error = 0; |
143 |
|
144 |
if (acl_type == ACL_TYPE_DEFAULT && (flag & FTW_D) == 0) { |
145 |
warnx("%s: default ACL may only be set on a directory", |
146 |
path); |
147 |
carried_error++; |
148 |
return (R_flag == 0); |
149 |
} |
150 |
|
151 |
if (h_flag) |
152 |
ret = lpathconf(path, _PC_ACL_NFS4); |
153 |
else |
154 |
ret = pathconf(path, _PC_ACL_NFS4); |
155 |
if (ret > 0) { |
156 |
if (acl_type == ACL_TYPE_DEFAULT) { |
157 |
warnx("%s: there are no default entries " |
158 |
"in NFSv4 ACLs", path); |
159 |
carried_error++; |
160 |
return (R_flag == 0); |
161 |
} |
162 |
acl_type = ACL_TYPE_NFS4; |
163 |
} else if (ret == 0) { |
164 |
if (acl_type == ACL_TYPE_NFS4) |
165 |
acl_type = ACL_TYPE_ACCESS; |
166 |
} else if (ret < 0 && errno != EINVAL) { |
167 |
warn("%s: pathconf(..., _PC_ACL_NFS4) failed", |
168 |
path); |
169 |
} |
170 |
|
171 |
if (h_flag) |
172 |
acl = acl_get_link_np(path, acl_type); |
173 |
else |
174 |
acl = acl_get_file(path, acl_type); |
175 |
if (acl == NULL) { |
176 |
if (h_flag) |
177 |
warn("%s: acl_get_link_np() failed", |
178 |
path); |
179 |
else |
180 |
warn("%s: acl_get_file() failed", |
181 |
path); |
182 |
carried_error++; |
183 |
return (R_flag == 0); |
184 |
} |
185 |
|
186 |
/* cycle through each option */ |
187 |
TAILQ_FOREACH(entry, &entrylist, next) { |
188 |
if (local_error) |
189 |
continue; |
190 |
|
191 |
switch(entry->op) { |
192 |
case OP_ADD_ACL: |
193 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
194 |
&& (flag & FTW_D) == 0) { |
195 |
acl_backup = acl_dup(entry->acl); |
196 |
entry->acl = sanitize_inheritance(sb, entry->acl); |
197 |
if (entry->acl == (acl_t)NULL) { |
198 |
local_error++; |
199 |
break; |
200 |
} |
201 |
} |
202 |
local_error += add_acl(entry->acl, |
203 |
entry->entry_number, &acl, path); |
204 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
205 |
&& (flag & FTW_D) == 0) { |
206 |
acl_free(entry->acl); |
207 |
entry->acl = acl_backup; |
208 |
} |
209 |
break; |
210 |
case OP_MERGE_ACL: |
211 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
212 |
&& (flag & FTW_D) == 0) { |
213 |
acl_backup = acl_dup(entry->acl); |
214 |
entry->acl = sanitize_inheritance(sb, entry->acl); |
215 |
} |
216 |
local_error += merge_acl(entry->acl, &acl, |
217 |
path); |
218 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
219 |
&& (flag & FTW_D) == 0) { |
220 |
acl_free(entry->acl); |
221 |
entry->acl = acl_backup; |
222 |
} |
223 |
need_mask = 1; |
224 |
break; |
225 |
case OP_REMOVE_EXT: |
226 |
/* |
227 |
* Don't try to call remove_ext() for empty |
228 |
* default ACL. |
229 |
*/ |
230 |
if (acl_type == ACL_TYPE_DEFAULT && |
231 |
acl_get_entry(acl, ACL_FIRST_ENTRY, |
232 |
&unused_entry) == 0) { |
233 |
local_error += remove_default(&acl, |
234 |
path); |
235 |
break; |
236 |
} |
237 |
remove_ext(&acl, path); |
238 |
need_mask = 0; |
239 |
break; |
240 |
case OP_REMOVE_DEF: |
241 |
if (acl_type == ACL_TYPE_NFS4) { |
242 |
warnx("%s: there are no default entries in NFSv4 ACLs; " |
243 |
"cannot remove", path); |
244 |
local_error++; |
245 |
break; |
246 |
} |
247 |
if (acl_delete_def_file(path) == -1) { |
248 |
warn("%s: acl_delete_def_file() failed", |
249 |
path); |
250 |
local_error++; |
251 |
} |
252 |
if (acl_type == ACL_TYPE_DEFAULT) |
253 |
local_error += remove_default(&acl, |
254 |
path); |
255 |
need_mask = 0; |
256 |
break; |
257 |
case OP_REMOVE_ACL: |
258 |
local_error += remove_acl(entry->acl, &acl, |
259 |
path); |
260 |
need_mask = 1; |
261 |
break; |
262 |
case OP_REMOVE_BY_NUMBER: |
263 |
local_error += remove_by_number(entry->entry_number, |
264 |
&acl, path); |
265 |
need_mask = 1; |
266 |
break; |
267 |
} |
268 |
} |
269 |
|
270 |
/* |
271 |
* Don't try to set an empty default ACL; it will always fail. |
272 |
* Use acl_delete_def_file(3) instead. |
273 |
*/ |
274 |
if (acl_type == ACL_TYPE_DEFAULT && |
275 |
acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) { |
276 |
if (acl_delete_def_file(path) == -1) { |
277 |
warn("%s: acl_delete_def_file() failed", |
278 |
path); |
279 |
carried_error++; |
280 |
} |
281 |
return (R_flag == 0); |
282 |
} |
283 |
|
284 |
/* don't bother setting the ACL if something is broken */ |
285 |
if (local_error) { |
286 |
carried_error++; |
287 |
return (R_flag == 0); |
288 |
} |
289 |
|
290 |
if (acl_type != ACL_TYPE_NFS4 && need_mask && |
291 |
set_acl_mask(&acl, path) == -1) { |
292 |
warnx("%s: failed to set ACL mask", path); |
293 |
carried_error++; |
294 |
} else if (h_flag) { |
295 |
if (acl_set_link_np(path, acl_type, |
296 |
acl) == -1) { |
297 |
carried_error++; |
298 |
warn("%s: acl_set_link_np() failed", |
299 |
path); |
300 |
} |
301 |
} else { |
302 |
if (acl_set_file(path, acl_type, |
303 |
acl) == -1) { |
304 |
carried_error++; |
305 |
warn("%s: acl_set_file() failed", |
306 |
path); |
307 |
} |
308 |
} |
309 |
|
310 |
acl_free(acl); |
311 |
return (R_flag == 0); |
312 |
} |
313 |
|
91 |
static void |
314 |
static void |
92 |
usage(void) |
315 |
usage(void) |
93 |
{ |
316 |
{ |
94 |
|
317 |
|
95 |
fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] " |
318 |
fprintf(stderr, "usage: setfacl [-bdhknR] [-a position entries] " |
96 |
"[-m entries] [-M file] [-x entries] [-X file] [file ...]\n"); |
319 |
"[-m entries] [-M file] [-x entries] [-X file] [file ...]\n"); |
97 |
exit(1); |
320 |
exit(1); |
98 |
} |
321 |
} |
Lines 100-125
usage(void)
Link Here
|
100 |
int |
323 |
int |
101 |
main(int argc, char *argv[]) |
324 |
main(int argc, char *argv[]) |
102 |
{ |
325 |
{ |
103 |
acl_t acl; |
|
|
104 |
acl_type_t acl_type; |
105 |
acl_entry_t unused_entry; |
106 |
char filename[PATH_MAX]; |
326 |
char filename[PATH_MAX]; |
107 |
int local_error, carried_error, ch, i, entry_number, ret; |
327 |
int ch, i, entry_number; |
108 |
int h_flag; |
|
|
109 |
struct sf_file *file; |
328 |
struct sf_file *file; |
110 |
struct sf_entry *entry; |
329 |
struct sf_entry *entry; |
111 |
const char *fn_dup; |
330 |
const char *fn_dup; |
112 |
char *end; |
331 |
char *end; |
113 |
struct stat sb; |
|
|
114 |
|
332 |
|
115 |
acl_type = ACL_TYPE_ACCESS; |
333 |
acl_type = ACL_TYPE_ACCESS; |
116 |
carried_error = local_error = 0; |
334 |
carried_error = 0; |
117 |
h_flag = have_mask = have_stdin = n_flag = need_mask = 0; |
335 |
h_flag = have_mask = have_stdin = n_flag = need_mask = 0; |
|
|
336 |
R_flag = 0; |
118 |
|
337 |
|
119 |
TAILQ_INIT(&entrylist); |
338 |
TAILQ_INIT(&entrylist); |
120 |
TAILQ_INIT(&filelist); |
339 |
TAILQ_INIT(&filelist); |
121 |
|
340 |
|
122 |
while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1) |
341 |
while ((ch = getopt(argc, argv, "M:RX:a:bdhkm:nx:")) != -1) |
123 |
switch(ch) { |
342 |
switch(ch) { |
124 |
case 'M': |
343 |
case 'M': |
125 |
entry = zmalloc(sizeof(struct sf_entry)); |
344 |
entry = zmalloc(sizeof(struct sf_entry)); |
Lines 129-134
main(int argc, char *argv[])
Link Here
|
129 |
entry->op = OP_MERGE_ACL; |
348 |
entry->op = OP_MERGE_ACL; |
130 |
TAILQ_INSERT_TAIL(&entrylist, entry, next); |
349 |
TAILQ_INSERT_TAIL(&entrylist, entry, next); |
131 |
break; |
350 |
break; |
|
|
351 |
case 'R': |
352 |
R_flag = 1; |
353 |
break; |
132 |
case 'X': |
354 |
case 'X': |
133 |
entry = zmalloc(sizeof(struct sf_entry)); |
355 |
entry = zmalloc(sizeof(struct sf_entry)); |
134 |
entry->acl = get_acl_from_file(optarg); |
356 |
entry->acl = get_acl_from_file(optarg); |
Lines 227-383
main(int argc, char *argv[])
Link Here
|
227 |
|
449 |
|
228 |
/* cycle through each file */ |
450 |
/* cycle through each file */ |
229 |
TAILQ_FOREACH(file, &filelist, next) { |
451 |
TAILQ_FOREACH(file, &filelist, next) { |
230 |
local_error = 0; |
452 |
if (nftw(file->filename, walk_path, 5, h_flag ? FTW_PHYS : 0) < 0) { |
231 |
|
453 |
warn("%s: nftw() failed", file->filename); |
232 |
if (stat(file->filename, &sb) == -1) { |
|
|
233 |
warn("%s: stat() failed", file->filename); |
234 |
carried_error++; |
235 |
continue; |
236 |
} |
237 |
|
238 |
if (acl_type == ACL_TYPE_DEFAULT && S_ISDIR(sb.st_mode) == 0) { |
239 |
warnx("%s: default ACL may only be set on a directory", |
240 |
file->filename); |
241 |
carried_error++; |
242 |
continue; |
243 |
} |
244 |
|
245 |
if (h_flag) |
246 |
ret = lpathconf(file->filename, _PC_ACL_NFS4); |
247 |
else |
248 |
ret = pathconf(file->filename, _PC_ACL_NFS4); |
249 |
if (ret > 0) { |
250 |
if (acl_type == ACL_TYPE_DEFAULT) { |
251 |
warnx("%s: there are no default entries " |
252 |
"in NFSv4 ACLs", file->filename); |
253 |
carried_error++; |
254 |
continue; |
255 |
} |
256 |
acl_type = ACL_TYPE_NFS4; |
257 |
} else if (ret == 0) { |
258 |
if (acl_type == ACL_TYPE_NFS4) |
259 |
acl_type = ACL_TYPE_ACCESS; |
260 |
} else if (ret < 0 && errno != EINVAL) { |
261 |
warn("%s: pathconf(..., _PC_ACL_NFS4) failed", |
262 |
file->filename); |
263 |
} |
264 |
|
265 |
if (h_flag) |
266 |
acl = acl_get_link_np(file->filename, acl_type); |
267 |
else |
268 |
acl = acl_get_file(file->filename, acl_type); |
269 |
if (acl == NULL) { |
270 |
if (h_flag) |
271 |
warn("%s: acl_get_link_np() failed", |
272 |
file->filename); |
273 |
else |
274 |
warn("%s: acl_get_file() failed", |
275 |
file->filename); |
276 |
carried_error++; |
454 |
carried_error++; |
277 |
continue; |
455 |
continue; |
278 |
} |
456 |
} |
279 |
|
|
|
280 |
/* cycle through each option */ |
281 |
TAILQ_FOREACH(entry, &entrylist, next) { |
282 |
if (local_error) |
283 |
continue; |
284 |
|
285 |
switch(entry->op) { |
286 |
case OP_ADD_ACL: |
287 |
local_error += add_acl(entry->acl, |
288 |
entry->entry_number, &acl, file->filename); |
289 |
break; |
290 |
case OP_MERGE_ACL: |
291 |
local_error += merge_acl(entry->acl, &acl, |
292 |
file->filename); |
293 |
need_mask = 1; |
294 |
break; |
295 |
case OP_REMOVE_EXT: |
296 |
/* |
297 |
* Don't try to call remove_ext() for empty |
298 |
* default ACL. |
299 |
*/ |
300 |
if (acl_type == ACL_TYPE_DEFAULT && |
301 |
acl_get_entry(acl, ACL_FIRST_ENTRY, |
302 |
&unused_entry) == 0) { |
303 |
local_error += remove_default(&acl, |
304 |
file->filename); |
305 |
break; |
306 |
} |
307 |
remove_ext(&acl, file->filename); |
308 |
need_mask = 0; |
309 |
break; |
310 |
case OP_REMOVE_DEF: |
311 |
if (acl_type == ACL_TYPE_NFS4) { |
312 |
warnx("%s: there are no default entries in NFSv4 ACLs; " |
313 |
"cannot remove", file->filename); |
314 |
local_error++; |
315 |
break; |
316 |
} |
317 |
if (acl_delete_def_file(file->filename) == -1) { |
318 |
warn("%s: acl_delete_def_file() failed", |
319 |
file->filename); |
320 |
local_error++; |
321 |
} |
322 |
if (acl_type == ACL_TYPE_DEFAULT) |
323 |
local_error += remove_default(&acl, |
324 |
file->filename); |
325 |
need_mask = 0; |
326 |
break; |
327 |
case OP_REMOVE_ACL: |
328 |
local_error += remove_acl(entry->acl, &acl, |
329 |
file->filename); |
330 |
need_mask = 1; |
331 |
break; |
332 |
case OP_REMOVE_BY_NUMBER: |
333 |
local_error += remove_by_number(entry->entry_number, |
334 |
&acl, file->filename); |
335 |
need_mask = 1; |
336 |
break; |
337 |
} |
338 |
} |
339 |
|
340 |
/* |
341 |
* Don't try to set an empty default ACL; it will always fail. |
342 |
* Use acl_delete_def_file(3) instead. |
343 |
*/ |
344 |
if (acl_type == ACL_TYPE_DEFAULT && |
345 |
acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) { |
346 |
if (acl_delete_def_file(file->filename) == -1) { |
347 |
warn("%s: acl_delete_def_file() failed", |
348 |
file->filename); |
349 |
carried_error++; |
350 |
} |
351 |
continue; |
352 |
} |
353 |
|
354 |
/* don't bother setting the ACL if something is broken */ |
355 |
if (local_error) { |
356 |
carried_error++; |
357 |
continue; |
358 |
} |
359 |
|
360 |
if (acl_type != ACL_TYPE_NFS4 && need_mask && |
361 |
set_acl_mask(&acl, file->filename) == -1) { |
362 |
warnx("%s: failed to set ACL mask", file->filename); |
363 |
carried_error++; |
364 |
} else if (h_flag) { |
365 |
if (acl_set_link_np(file->filename, acl_type, |
366 |
acl) == -1) { |
367 |
carried_error++; |
368 |
warn("%s: acl_set_link_np() failed", |
369 |
file->filename); |
370 |
} |
371 |
} else { |
372 |
if (acl_set_file(file->filename, acl_type, |
373 |
acl) == -1) { |
374 |
carried_error++; |
375 |
warn("%s: acl_set_file() failed", |
376 |
file->filename); |
377 |
} |
378 |
} |
379 |
|
380 |
acl_free(acl); |
381 |
} |
457 |
} |
382 |
|
458 |
|
383 |
return (carried_error); |
459 |
return (carried_error); |