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-93
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 |
|
115 |
entry_id = ACL_FIRST_ENTRY; |
116 |
while (acl_get_entry(acl_new, entry_id, &acl_entry) == 1) { |
117 |
entry_id = ACL_NEXT_ENTRY; |
118 |
acl_get_flagset_np(acl_entry, &acl_flagset); |
119 |
if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY)) { |
120 |
acl_delete_entry(acl_new, acl_entry); |
121 |
continue; |
122 |
} |
123 |
acl_delete_flag_np(acl_flagset, ACL_ENTRY_FILE_INHERIT |
124 |
| ACL_ENTRY_DIRECTORY_INHERIT |
125 |
| ACL_ENTRY_NO_PROPAGATE_INHERIT); |
126 |
} |
127 |
|
128 |
return acl_new; |
129 |
} |
130 |
|
131 |
static int |
132 |
walk_path(const char *path, const struct stat *sb, int flag, struct FTW *ftwp __unused) |
133 |
{ |
134 |
acl_t acl, acl_backup; |
135 |
acl_entry_t unused_entry; |
136 |
struct sf_entry *entry; |
137 |
unsigned int local_error; |
138 |
int ret; |
139 |
|
140 |
local_error = 0; |
141 |
|
142 |
if (acl_type == ACL_TYPE_DEFAULT && (flag & FTW_D) == 0) { |
143 |
warnx("%s: default ACL may only be set on a directory", |
144 |
path); |
145 |
carried_error++; |
146 |
return (R_flag == 0); |
147 |
} |
148 |
|
149 |
if (h_flag) |
150 |
ret = lpathconf(path, _PC_ACL_NFS4); |
151 |
else |
152 |
ret = pathconf(path, _PC_ACL_NFS4); |
153 |
if (ret > 0) { |
154 |
if (acl_type == ACL_TYPE_DEFAULT) { |
155 |
warnx("%s: there are no default entries " |
156 |
"in NFSv4 ACLs", path); |
157 |
carried_error++; |
158 |
return (R_flag == 0); |
159 |
} |
160 |
acl_type = ACL_TYPE_NFS4; |
161 |
} else if (ret == 0) { |
162 |
if (acl_type == ACL_TYPE_NFS4) |
163 |
acl_type = ACL_TYPE_ACCESS; |
164 |
} else if (ret < 0 && errno != EINVAL) { |
165 |
warn("%s: pathconf(..., _PC_ACL_NFS4) failed", |
166 |
path); |
167 |
} |
168 |
|
169 |
if (h_flag) |
170 |
acl = acl_get_link_np(path, acl_type); |
171 |
else |
172 |
acl = acl_get_file(path, acl_type); |
173 |
if (acl == NULL) { |
174 |
if (h_flag) |
175 |
warn("%s: acl_get_link_np() failed", |
176 |
path); |
177 |
else |
178 |
warn("%s: acl_get_file() failed", |
179 |
path); |
180 |
carried_error++; |
181 |
return (R_flag == 0); |
182 |
} |
183 |
|
184 |
/* cycle through each option */ |
185 |
TAILQ_FOREACH(entry, &entrylist, next) { |
186 |
if (local_error) |
187 |
continue; |
188 |
|
189 |
switch(entry->op) { |
190 |
case OP_ADD_ACL: |
191 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
192 |
&& (flag & FTW_D) == 0) { |
193 |
acl_backup = acl_dup(entry->acl); |
194 |
entry->acl = sanitize_inheritance(sb, entry->acl); |
195 |
} |
196 |
local_error += add_acl(entry->acl, |
197 |
entry->entry_number, &acl, path); |
198 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
199 |
&& (flag & FTW_D) == 0) { |
200 |
acl_free(entry->acl); |
201 |
entry->acl = acl_backup; |
202 |
} |
203 |
break; |
204 |
case OP_MERGE_ACL: |
205 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
206 |
&& (flag & FTW_D) == 0) { |
207 |
acl_backup = acl_dup(entry->acl); |
208 |
entry->acl = sanitize_inheritance(sb, entry->acl); |
209 |
} |
210 |
local_error += merge_acl(entry->acl, &acl, |
211 |
path); |
212 |
if (R_flag && acl_type == ACL_TYPE_NFS4 |
213 |
&& (flag & FTW_D) == 0) { |
214 |
acl_free(entry->acl); |
215 |
entry->acl = acl_backup; |
216 |
} |
217 |
need_mask = 1; |
218 |
break; |
219 |
case OP_REMOVE_EXT: |
220 |
/* |
221 |
* Don't try to call remove_ext() for empty |
222 |
* default ACL. |
223 |
*/ |
224 |
if (acl_type == ACL_TYPE_DEFAULT && |
225 |
acl_get_entry(acl, ACL_FIRST_ENTRY, |
226 |
&unused_entry) == 0) { |
227 |
local_error += remove_default(&acl, |
228 |
path); |
229 |
break; |
230 |
} |
231 |
remove_ext(&acl, path); |
232 |
need_mask = 0; |
233 |
break; |
234 |
case OP_REMOVE_DEF: |
235 |
if (acl_type == ACL_TYPE_NFS4) { |
236 |
warnx("%s: there are no default entries in NFSv4 ACLs; " |
237 |
"cannot remove", path); |
238 |
local_error++; |
239 |
break; |
240 |
} |
241 |
if (acl_delete_def_file(path) == -1) { |
242 |
warn("%s: acl_delete_def_file() failed", |
243 |
path); |
244 |
local_error++; |
245 |
} |
246 |
if (acl_type == ACL_TYPE_DEFAULT) |
247 |
local_error += remove_default(&acl, |
248 |
path); |
249 |
need_mask = 0; |
250 |
break; |
251 |
case OP_REMOVE_ACL: |
252 |
local_error += remove_acl(entry->acl, &acl, |
253 |
path); |
254 |
need_mask = 1; |
255 |
break; |
256 |
case OP_REMOVE_BY_NUMBER: |
257 |
local_error += remove_by_number(entry->entry_number, |
258 |
&acl, path); |
259 |
need_mask = 1; |
260 |
break; |
261 |
} |
262 |
} |
263 |
|
264 |
/* |
265 |
* Don't try to set an empty default ACL; it will always fail. |
266 |
* Use acl_delete_def_file(3) instead. |
267 |
*/ |
268 |
if (acl_type == ACL_TYPE_DEFAULT && |
269 |
acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) { |
270 |
if (acl_delete_def_file(path) == -1) { |
271 |
warn("%s: acl_delete_def_file() failed", |
272 |
path); |
273 |
carried_error++; |
274 |
} |
275 |
return (R_flag == 0); |
276 |
} |
277 |
|
278 |
/* don't bother setting the ACL if something is broken */ |
279 |
if (local_error) { |
280 |
carried_error++; |
281 |
return (R_flag == 0); |
282 |
} |
283 |
|
284 |
if (acl_type != ACL_TYPE_NFS4 && need_mask && |
285 |
set_acl_mask(&acl, path) == -1) { |
286 |
warnx("%s: failed to set ACL mask", path); |
287 |
carried_error++; |
288 |
} else if (h_flag) { |
289 |
if (acl_set_link_np(path, acl_type, |
290 |
acl) == -1) { |
291 |
carried_error++; |
292 |
warn("%s: acl_set_link_np() failed", |
293 |
path); |
294 |
} |
295 |
} else { |
296 |
if (acl_set_file(path, acl_type, |
297 |
acl) == -1) { |
298 |
carried_error++; |
299 |
warn("%s: acl_set_file() failed", |
300 |
path); |
301 |
} |
302 |
} |
303 |
|
304 |
acl_free(acl); |
305 |
return (R_flag == 0); |
306 |
} |
307 |
|
91 |
static void |
308 |
static void |
92 |
usage(void) |
309 |
usage(void) |
93 |
{ |
310 |
{ |
Lines 100-125
usage(void)
Link Here
|
100 |
int |
317 |
int |
101 |
main(int argc, char *argv[]) |
318 |
main(int argc, char *argv[]) |
102 |
{ |
319 |
{ |
103 |
acl_t acl; |
|
|
104 |
acl_type_t acl_type; |
105 |
acl_entry_t unused_entry; |
106 |
char filename[PATH_MAX]; |
320 |
char filename[PATH_MAX]; |
107 |
int local_error, carried_error, ch, i, entry_number, ret; |
321 |
int ch, i, entry_number; |
108 |
int h_flag; |
|
|
109 |
struct sf_file *file; |
322 |
struct sf_file *file; |
110 |
struct sf_entry *entry; |
323 |
struct sf_entry *entry; |
111 |
const char *fn_dup; |
324 |
const char *fn_dup; |
112 |
char *end; |
325 |
char *end; |
113 |
struct stat sb; |
|
|
114 |
|
326 |
|
115 |
acl_type = ACL_TYPE_ACCESS; |
327 |
acl_type = ACL_TYPE_ACCESS; |
116 |
carried_error = local_error = 0; |
328 |
carried_error = 0; |
117 |
h_flag = have_mask = have_stdin = n_flag = need_mask = 0; |
329 |
h_flag = have_mask = have_stdin = n_flag = need_mask = 0; |
|
|
330 |
R_flag = 0; |
118 |
|
331 |
|
119 |
TAILQ_INIT(&entrylist); |
332 |
TAILQ_INIT(&entrylist); |
120 |
TAILQ_INIT(&filelist); |
333 |
TAILQ_INIT(&filelist); |
121 |
|
334 |
|
122 |
while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1) |
335 |
while ((ch = getopt(argc, argv, "M:RX:a:bdhkm:nx:")) != -1) |
123 |
switch(ch) { |
336 |
switch(ch) { |
124 |
case 'M': |
337 |
case 'M': |
125 |
entry = zmalloc(sizeof(struct sf_entry)); |
338 |
entry = zmalloc(sizeof(struct sf_entry)); |
Lines 129-134
main(int argc, char *argv[])
Link Here
|
129 |
entry->op = OP_MERGE_ACL; |
342 |
entry->op = OP_MERGE_ACL; |
130 |
TAILQ_INSERT_TAIL(&entrylist, entry, next); |
343 |
TAILQ_INSERT_TAIL(&entrylist, entry, next); |
131 |
break; |
344 |
break; |
|
|
345 |
case 'R': |
346 |
R_flag = 1; |
347 |
break; |
132 |
case 'X': |
348 |
case 'X': |
133 |
entry = zmalloc(sizeof(struct sf_entry)); |
349 |
entry = zmalloc(sizeof(struct sf_entry)); |
134 |
entry->acl = get_acl_from_file(optarg); |
350 |
entry->acl = get_acl_from_file(optarg); |
Lines 227-383
main(int argc, char *argv[])
Link Here
|
227 |
|
443 |
|
228 |
/* cycle through each file */ |
444 |
/* cycle through each file */ |
229 |
TAILQ_FOREACH(file, &filelist, next) { |
445 |
TAILQ_FOREACH(file, &filelist, next) { |
230 |
local_error = 0; |
446 |
if (nftw(file->filename, walk_path, 5, h_flag ? FTW_PHYS : 0) < 0) { |
231 |
|
447 |
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++; |
448 |
carried_error++; |
277 |
continue; |
449 |
continue; |
278 |
} |
450 |
} |
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 |
} |
451 |
} |
382 |
|
452 |
|
383 |
return (carried_error); |
453 |
return (carried_error); |